已合并
[Feature][op][eqbsa-02] add eqbsa operator, attention infra, and enable build #514
lanwangli创建于 20 天前
[Feature][op][eqbsa-02] add eqbsa operator, attention infra, and enable build #514
已合并
共 83 个文件变更+22792-1
| @@ -36,7 +36,8 @@ if [ ! -f ${msopgen} ]; then | |||
| 36 | echo "${msopgen} not exists" | 36 | echo "${msopgen} not exists" |
| 37 | exit 1 | 37 | exit 1 |
| 38 | fi | 38 | fi |
| 39 | -ascendc_ops=${ASCEND_OP_NAME:-'laser_attention;la_preprocess;ada_block_sparse_attention;sparse_block_estimate;norm_rope_concat;quant_flash_attn;quant_flash_attn_metadata;fused_infer_attention_score;mul_add'} | 39 | + |
| 40 | +ascendc_ops=${ASCEND_OP_NAME:-'laser_attention;la_preprocess;ada_block_sparse_attention;sparse_block_estimate;norm_rope_concat;quant_flash_attn;quant_flash_attn_metadata;fused_infer_attention_score;eagle_quant_block_sparse_attention;mul_add'} | ||
| 40 | 41 | ||
| 41 | # ascend950 backend requires CANN 9.0+; remove ascend950 when CANN < 9.0 | 42 | # ascend950 backend requires CANN 9.0+; remove ascend950 when CANN < 9.0 |
| 42 | default_compute_unit='ascend910;ascend910b;ascend910_93;ascend950' | 43 | default_compute_unit='ascend910;ascend910b;ascend910_93;ascend950' |
Acsrc/ops/eagle_quant_block_sparse_attention/op_api/aclnn_eagle_quant_block_sparse_attention.cpp+332-0
| @@ -0,0 +1,332 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +using namespace op; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +extern "C" { | ||
| 30 | + | ||
| 31 | + | ||
| 32 | +namespace { | ||
| 33 | + | ||
| 34 | +static constexpr uint64_t LSE_OUT = 1; | ||
| 35 | + | ||
| 36 | +static bool CheckDataType(const aclTensor *query, | ||
| 37 | + const aclTensor *key, | ||
| 38 | + const aclTensor *value) | ||
| 39 | +{ | ||
| 40 | + const DataType qDtype = query->GetDataType(); | ||
| 41 | + const DataType kDtype = key->GetDataType(); | ||
| 42 | + const DataType vDtype = value->GetDataType(); | ||
| 43 | + | ||
| 44 | + | ||
| 45 | + static const std::unordered_map<DataType, std::vector<DataType>> validKvType = { | ||
| 46 | + {DataType::DT_FLOAT16, {DataType::DT_FLOAT16}}, | ||
| 47 | + {DataType::DT_BF16, {DataType::DT_BF16}}, | ||
| 48 | + {DataType::DT_INT8, {DataType::DT_INT8, DataType::DT_FLOAT8_E4M3FN}} | ||
| 49 | + }; | ||
| 50 | + | ||
| 51 | + auto iter = validKvType.find(qDtype); | ||
| 52 | + if (iter == validKvType.end()) { | ||
| 53 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Unsupported query datatype %d.", static_cast<int>(qDtype)); | ||
| 54 | + return false; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + if (std::find(iter->second.begin(), iter->second.end(), kDtype) == iter->second.end() || | ||
| 58 | + std::find(iter->second.begin(), iter->second.end(), vDtype) == iter->second.end()) { | ||
| 59 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Key/Value datatype mismatch with query."); | ||
| 60 | + return false; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + return true; | ||
| 64 | +} | ||
| 65 | + | ||
| 66 | + | ||
| 67 | +static aclnnStatus CheckMandatoryTensors(const aclTensor *query, | ||
| 68 | + const aclTensor *key, | ||
| 69 | + const aclTensor *value) | ||
| 70 | +{ | ||
| 71 | + CHECK_RET(query != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 72 | + CHECK_RET(key != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 73 | + CHECK_RET(value != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 74 | + return ACLNN_SUCCESS; | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +static aclnnStatus ParseblockShapeOptional(const aclIntArray *blockShapeOptional) | ||
| 78 | +{ | ||
| 79 | + if (blockShapeOptional == nullptr) { | ||
| 80 | + OP_LOGE(ACLNN_ERR_PARAM_NULLPTR, "blockShapeOptional is null."); | ||
| 81 | + return ACLNN_ERR_PARAM_NULLPTR; | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + uint64_t size = blockShapeOptional->Size(); | ||
| 85 | + if (size < 2) { | ||
| 86 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "blockShapeOptional must contain at least two elements [x, y]."); | ||
| 87 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + const int64_t *data = blockShapeOptional->GetData(); | ||
| 91 | + if (data == nullptr) { | ||
| 92 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "blockShapeOptional data is null."); | ||
| 93 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + if (data[0] <= 0 || data[1] <= 0) { | ||
| 97 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "blockShapeOptional values must be positive, got [%ld, %ld].", data[0], data[1]); | ||
| 98 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + return ACLNN_SUCCESS; | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +static aclnnStatus ValidateParams(const aclTensor *query, | ||
| 105 | + const aclTensor *key, | ||
| 106 | + const aclTensor *value, | ||
| 107 | + char *qInputLayout, | ||
| 108 | + char *kvInputLayout, | ||
| 109 | + const aclIntArray *blockShapeOptional) | ||
| 110 | +{ | ||
| 111 | + CHECK_RET(CheckMandatoryTensors(query, key, value) == ACLNN_SUCCESS, | ||
| 112 | + ACLNN_ERR_PARAM_NULLPTR); | ||
| 113 | + | ||
| 114 | + if (!CheckDataType(query, key, value)) { | ||
| 115 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + if (qInputLayout == nullptr || kvInputLayout == nullptr) { | ||
| 119 | + OP_LOGE(ACLNN_ERR_PARAM_NULLPTR, "Input layout strings are null."); | ||
| 120 | + return ACLNN_ERR_PARAM_NULLPTR; | ||
| 121 | + } | ||
| 122 | + std::string qLayout(qInputLayout); | ||
| 123 | + std::string kvLayout(kvInputLayout); | ||
| 124 | + | ||
| 125 | + // 验证Q layout | ||
| 126 | + if (qLayout != "TND" && qLayout != "BNSD") { | ||
| 127 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "qInputLayout only supports TND or BNSD, got %s.", qLayout.c_str()); | ||
| 128 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + // 验证KV layout | ||
| 132 | + if (kvLayout != "TND" && kvLayout != "BNSD") { | ||
| 133 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "kvInputLayout only supports TND or BNSD, got %s.", kvLayout.c_str()); | ||
| 134 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + // 验证Q和KV格式一致性:如果其中一个是BNSD,另一个也必须是BNSD | ||
| 138 | + bool qIsBNSD = (qLayout == "BNSD"); | ||
| 139 | + bool kvIsBNSD = (kvLayout == "BNSD"); | ||
| 140 | + if (qIsBNSD != kvIsBNSD) { | ||
| 141 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, | ||
| 142 | + "Q and KV layouts must match: if one is BNSD, the other must also be BNSD. " | ||
| 143 | + "Q layout: %s, KV layout: %s", qLayout.c_str(), kvLayout.c_str()); | ||
| 144 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + return ParseblockShapeOptional(blockShapeOptional); | ||
| 148 | +} | ||
| 149 | + | ||
| 150 | +static aclnnStatus MakeContiguous(const aclTensor *&query, | ||
| 151 | + const aclTensor *&key, | ||
| 152 | + const aclTensor *&value, | ||
| 153 | + const aclTensor *&blockSparseMaskOptional, | ||
| 154 | + const aclTensor *&attenMaskOptional, | ||
| 155 | + const aclTensor *&blockTableOptional, | ||
| 156 | + const aclTensor *&queryScaleOptional, | ||
| 157 | + const aclTensor *&keyScaleOptional, | ||
| 158 | + const aclTensor *&valueScaleOptional, | ||
| 159 | + aclOpExecutor *executor) | ||
| 160 | +{ | ||
| 161 | + query = l0op::Contiguous(query, executor); | ||
| 162 | + CHECK_RET(query != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 163 | + | ||
| 164 | + key = l0op::Contiguous(key, executor); | ||
| 165 | + CHECK_RET(key != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 166 | + | ||
| 167 | + value = l0op::Contiguous(value, executor); | ||
| 168 | + CHECK_RET(value != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 169 | + //新增blockSparseMaskOptional非空校验且必须为四维 | ||
| 170 | + | ||
| 171 | + if (blockSparseMaskOptional != nullptr) { | ||
| 172 | + blockSparseMaskOptional = l0op::Contiguous(blockSparseMaskOptional, executor); | ||
| 173 | + CHECK_RET(blockSparseMaskOptional != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 174 | + if (blockSparseMaskOptional->GetStorageShape().GetDimNum() != 4) { | ||
| 175 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, | ||
| 176 | + "blockSparseMask must be 4D tensor"); | ||
| 177 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 178 | + } | ||
| 179 | + //CHECK_RET(blockSparseMaskOptional->GetStorageShape().GetDim() == 4, "blockSparseMask must be 4D tensor"); | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + if (attenMaskOptional != nullptr) { | ||
| 183 | + attenMaskOptional = l0op::Contiguous(attenMaskOptional, executor); | ||
| 184 | + CHECK_RET(attenMaskOptional != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + if (blockTableOptional != nullptr) { | ||
| 188 | + blockTableOptional = l0op::Contiguous(blockTableOptional, executor); | ||
| 189 | + CHECK_RET(blockTableOptional != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + if (queryScaleOptional != nullptr) { | ||
| 193 | + queryScaleOptional = l0op::Contiguous(queryScaleOptional, executor); | ||
| 194 | + CHECK_RET(queryScaleOptional != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + if (keyScaleOptional != nullptr) { | ||
| 198 | + keyScaleOptional = l0op::Contiguous(keyScaleOptional, executor); | ||
| 199 | + CHECK_RET(keyScaleOptional != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + if (valueScaleOptional != nullptr) { | ||
| 203 | + valueScaleOptional = l0op::Contiguous(valueScaleOptional, executor); | ||
| 204 | + CHECK_RET(valueScaleOptional != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 205 | + } | ||
| 206 | + | ||
| 207 | + return ACLNN_SUCCESS; | ||
| 208 | +} | ||
| 209 | + | ||
| 210 | +static aclnnStatus ValidateAdditionalParams(int64_t innerPrecise, | ||
| 211 | + const aclTensor *attentionOut, | ||
| 212 | + uint64_t *workspaceSize, | ||
| 213 | + aclOpExecutor **executor) | ||
| 214 | +{ | ||
| 215 | + if (innerPrecise != 0 && innerPrecise != 1 && innerPrecise != 4) { | ||
| 216 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "innerPrecise must be 0 or 1 or 4, got %ld.", | ||
| 217 | + innerPrecise); | ||
| 218 | + return ACLNN_ERR_PARAM_INVALID; | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + CHECK_RET(attentionOut != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 222 | + CHECK_RET(workspaceSize != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 223 | + CHECK_RET(executor != nullptr, ACLNN_ERR_PARAM_NULLPTR); | ||
| 224 | + | ||
| 225 | + return ACLNN_SUCCESS; | ||
| 226 | +} | ||
| 227 | + | ||
| 228 | +static string ConvertLayoutString(char *layoutStr) | ||
| 229 | +{ | ||
| 230 | + return op::ToString(layoutStr).GetString(); | ||
| 231 | +} | ||
| 232 | + | ||
| 233 | +} // namespace | ||
| 234 | + | ||
| 235 | +__attribute__((visibility("default"))) aclnnStatus aclnnEagleQuantBlockSparseAttentionGetWorkspaceSize( | ||
| 236 | + const aclTensor *query, | ||
| 237 | + const aclTensor *key, | ||
| 238 | + const aclTensor *value, | ||
| 239 | + const aclTensor *blockSparseMask, | ||
| 240 | + const aclTensor *attenMaskOptional, | ||
| 241 | + const aclIntArray *blockShape, | ||
| 242 | + const aclIntArray *actualSeqLengthsOptional, | ||
| 243 | + const aclIntArray *actualSeqLengthsKvOptional, | ||
| 244 | + const aclTensor *blockTableOptional, | ||
| 245 | + const aclTensor *queryScaleOptional, | ||
| 246 | + const aclTensor *keyScaleOptional, | ||
| 247 | + const aclTensor *valueScaleOptional, | ||
| 248 | + char *qInputLayout, | ||
| 249 | + char *kvInputLayout, | ||
| 250 | + int64_t numKeyValueHeads, | ||
| 251 | + int64_t maskType, | ||
| 252 | + double scaleValue, | ||
| 253 | + int64_t innerPrecise, | ||
| 254 | + int64_t blockSize, | ||
| 255 | + int64_t preTokens, | ||
| 256 | + int64_t nextTokens, | ||
| 257 | + int64_t softmaxLseFlag, | ||
| 258 | + aclTensor *attentionOut, | ||
| 259 | + aclTensor *softmaxLseOptional, | ||
| 260 | + uint64_t *workspaceSize, | ||
| 261 | + aclOpExecutor **executor) | ||
| 262 | +{ | ||
| 263 | + aclnnStatus ret = ValidateParams(query, key, value, | ||
| 264 | + qInputLayout, kvInputLayout, blockShape); | ||
| 265 | + if (ret != ACLNN_SUCCESS) { | ||
| 266 | + return ret; | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + ret = ValidateAdditionalParams(innerPrecise, attentionOut, workspaceSize, executor); | ||
| 270 | + if (ret != ACLNN_SUCCESS) { | ||
| 271 | + return ret; | ||
| 272 | + } | ||
| 273 | + //去掉了idx ,idxnums | ||
| 274 | + L2_DFX_PHASE_1(aclnnEagleQuantBlockSparseAttention, | ||
| 275 | + DFX_IN(query, key, value, blockSparseMask, attenMaskOptional, blockShape, actualSeqLengthsOptional, | ||
| 276 | + queryScaleOptional, keyScaleOptional, valueScaleOptional, | ||
| 277 | + actualSeqLengthsKvOptional, blockTableOptional, qInputLayout, qInputLayout, numKeyValueHeads, | ||
| 278 | + maskType, scaleValue, innerPrecise, blockSize, preTokens, nextTokens, softmaxLseFlag), | ||
| 279 | + DFX_OUT(attentionOut, softmaxLseOptional)); | ||
| 280 | + | ||
| 281 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 282 | + CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 283 | + auto *executorImpl = uniqueExecutor.get(); | ||
| 284 | + //新增blockSparseMaskOptional参数 | ||
| 285 | + ret = MakeContiguous(query, key, value, blockSparseMask, attenMaskOptional, blockTableOptional, | ||
| 286 | + queryScaleOptional, keyScaleOptional, valueScaleOptional, | ||
| 287 | + executorImpl); | ||
| 288 | + if (ret != ACLNN_SUCCESS) { | ||
| 289 | + return ret; | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + string qInputLayoutStr = ConvertLayoutString(qInputLayout); | ||
| 293 | + string kvInputLayoutStr = ConvertLayoutString(kvInputLayout); | ||
| 294 | + //新增blockSparseMaskOptional参数 | ||
| 295 | + auto outputs = l0op::EagleQuantBlockSparseAttention(query, key, value, | ||
| 296 | + blockSparseMask, attenMaskOptional, blockShape, actualSeqLengthsOptional, | ||
| 297 | + actualSeqLengthsKvOptional, blockTableOptional, | ||
| 298 | + queryScaleOptional, keyScaleOptional, valueScaleOptional, | ||
| 299 | + qInputLayoutStr.c_str(), kvInputLayoutStr.c_str(), numKeyValueHeads, | ||
| 300 | + maskType, scaleValue, innerPrecise, blockSize, preTokens, nextTokens, softmaxLseFlag, executorImpl, | ||
| 301 | + attentionOut->GetDataType()); | ||
| 302 | + if (outputs[0] == nullptr || outputs[1] == nullptr) { | ||
| 303 | + OP_LOGE(ACLNN_ERR_INNER_NULLPTR, "EagleQuantBlockSparseAttention returned nullptr outputs."); | ||
| 304 | + return ACLNN_ERR_INNER_NULLPTR; | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + auto viewCopyResult = l0op::ViewCopy(outputs[0], attentionOut, executorImpl); | ||
| 308 | + CHECK_RET(viewCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 309 | + if (softmaxLseFlag == LSE_OUT) { | ||
| 310 | + auto viewCopyLseResult = l0op::ViewCopy(outputs[1], softmaxLseOptional, executorImpl); | ||
| 311 | + CHECK_RET(viewCopyLseResult != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 312 | + } | ||
| 313 | + | ||
| 314 | + *workspaceSize = executorImpl->GetWorkspaceSize(); | ||
| 315 | + uniqueExecutor.ReleaseTo(executor); | ||
| 316 | + return ACLNN_SUCCESS; | ||
| 317 | +} | ||
| 318 | + | ||
| 319 | +__attribute__((visibility("default"))) aclnnStatus aclnnEagleQuantBlockSparseAttention( | ||
| 320 | + void *workspace, | ||
| 321 | + uint64_t workspaceSize, | ||
| 322 | + aclOpExecutor *executor, | ||
| 323 | + aclrtStream stream) | ||
| 324 | +{ | ||
| 325 | + L2_DFX_PHASE_2(aclnnEagleQuantBlockSparseAttention); | ||
| 326 | + return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); | ||
| 327 | +} | ||
| 328 | + | ||
| 329 | + | ||
| 330 | +} | ||
| 331 | + | ||
| 332 | + | ||
| @@ -0,0 +1,59 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +extern "C" { | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +__attribute__((visibility("default"))) aclnnStatus aclnnEagleQuantBlockSparseAttentionGetWorkspaceSize( | ||
| 21 | + const aclTensor *query, | ||
| 22 | + const aclTensor *key, | ||
| 23 | + const aclTensor *value, | ||
| 24 | + const aclTensor *blockSparseMaskOptional, | ||
| 25 | + const aclTensor *attenMaskOptional, | ||
| 26 | + const aclIntArray *blockShapeOptional, | ||
| 27 | + const aclIntArray *actualSeqLengthsOptional, | ||
| 28 | + const aclIntArray *actualSeqLengthsKvOptional, | ||
| 29 | + const aclTensor *blockTableOptional, | ||
| 30 | + const aclTensor *queryScaleOptional, | ||
| 31 | + const aclTensor *keyScaleOptional, | ||
| 32 | + const aclTensor *valueSclaleOptional, | ||
| 33 | + char *qInputLayout, | ||
| 34 | + char *kvInputLayout, | ||
| 35 | + int64_t numKeyValueHeads, | ||
| 36 | + int64_t maskType, | ||
| 37 | + double scaleValue, | ||
| 38 | + int64_t innerPrecise, | ||
| 39 | + int64_t blockSize, | ||
| 40 | + int64_t preTokens, | ||
| 41 | + int64_t nextTokens, | ||
| 42 | + int64_t softmaxLseFlag, | ||
| 43 | + aclTensor *attentionOut, | ||
| 44 | + aclTensor *softmaxLseOptional, | ||
| 45 | + uint64_t *workspaceSize, | ||
| 46 | + aclOpExecutor **executor); | ||
| 47 | + | ||
| 48 | +__attribute__((visibility("default"))) aclnnStatus aclnnEagleQuantBlockSparseAttention( | ||
| 49 | + void *workspace, | ||
| 50 | + uint64_t workspaceSize, | ||
| 51 | + aclOpExecutor *executor, | ||
| 52 | + aclrtStream stream); | ||
| 53 | + | ||
| 54 | + | ||
| 55 | +} | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + | ||
| 59 | + | ||
| @@ -0,0 +1,125 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file eagle_quant_block_sparse_attention.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +using namespace op; | ||
| 23 | + | ||
| 24 | +namespace l0op { | ||
| 25 | + | ||
| 26 | +OP_TYPE_REGISTER(EagleQuantBlockSparseAttention); | ||
| 27 | + | ||
| 28 | +static const aclTensor *ConvertIntArrayToTensor(const aclIntArray *intArray, | ||
| 29 | + aclOpExecutor *executor, | ||
| 30 | + DataType dtype) | ||
| 31 | +{ | ||
| 32 | + if (intArray != nullptr) { | ||
| 33 | + const aclTensor *tensor = executor->ConvertToTensor(intArray, dtype); | ||
| 34 | + auto mutableTensor = const_cast<aclTensor *>(tensor); | ||
| 35 | + mutableTensor->SetStorageFormat(Format::FORMAT_ND); | ||
| 36 | + mutableTensor->SetViewFormat(Format::FORMAT_ND); | ||
| 37 | + mutableTensor->SetOriginalFormat(Format::FORMAT_ND); | ||
| 38 | + return tensor; | ||
| 39 | + } | ||
| 40 | + return executor->AllocTensor(dtype, Format::FORMAT_ND, Format::FORMAT_ND); | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +const std::array<const aclTensor *, 2> EagleQuantBlockSparseAttention( | ||
| 44 | + const aclTensor *query, | ||
| 45 | + const aclTensor *key, | ||
| 46 | + const aclTensor *value, | ||
| 47 | + const aclTensor *blockSparseMaskOptional, | ||
| 48 | + const aclTensor *attenMaskOptional, | ||
| 49 | + const aclIntArray *blockShapeOptional, | ||
| 50 | + const aclIntArray *actualSeqLengthsOptional, | ||
| 51 | + const aclIntArray *actualSeqLengthsKvOptional, | ||
| 52 | + const aclTensor *blockTableOptional, | ||
| 53 | + const aclTensor *queryScaleOptional, | ||
| 54 | + const aclTensor *keyScaleOptional, | ||
| 55 | + const aclTensor *valueScaleOptional, | ||
| 56 | + const char *qInputLayout, | ||
| 57 | + const char *kvInputLayout, | ||
| 58 | + int64_t numKeyValueHeads, | ||
| 59 | + int64_t maskType, | ||
| 60 | + double scaleValue, | ||
| 61 | + int64_t innerPrecise, | ||
| 62 | + int64_t blockSize, | ||
| 63 | + int64_t preTokens, | ||
| 64 | + int64_t nextTokens, | ||
| 65 | + int64_t softmaxLseFlag, | ||
| 66 | + aclOpExecutor *executor, | ||
| 67 | + DataType outDType | ||
| 68 | + ) | ||
| 69 | +{ | ||
| 70 | + const char *safeKvInputLayout = (kvInputLayout != nullptr) ? kvInputLayout : qInputLayout; | ||
| 71 | + | ||
| 72 | + L0_DFX(EagleQuantBlockSparseAttention, query, key, value, blockSparseMaskOptional, | ||
| 73 | + attenMaskOptional, blockShapeOptional, actualSeqLengthsOptional, actualSeqLengthsKvOptional, | ||
| 74 | + blockTableOptional, queryScaleOptional, keyScaleOptional, valueScaleOptional, | ||
| 75 | + qInputLayout, safeKvInputLayout, numKeyValueHeads, | ||
| 76 | + maskType, scaleValue, innerPrecise, blockSize, preTokens, nextTokens, softmaxLseFlag); | ||
| 77 | + | ||
| 78 | + const aclTensor *blockShapeOptionalTensor = nullptr; | ||
| 79 | + if (blockShapeOptional) { | ||
| 80 | + blockShapeOptionalTensor = ConvertIntArrayToTensor(blockShapeOptional, executor, DataType::DT_INT64); | ||
| 81 | + } | ||
| 82 | + const aclTensor *actualSeqTensor = nullptr; | ||
| 83 | + if (actualSeqLengthsOptional) { | ||
| 84 | + actualSeqTensor = ConvertIntArrayToTensor(actualSeqLengthsOptional, executor, DataType::DT_INT64); | ||
| 85 | + } | ||
| 86 | + const aclTensor *actualSeqKvTensor = nullptr; | ||
| 87 | + if (actualSeqLengthsKvOptional) { | ||
| 88 | + actualSeqKvTensor = ConvertIntArrayToTensor(actualSeqLengthsKvOptional, executor, DataType::DT_INT64); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + auto attentionOutTensor = executor->AllocTensor(outDType, Format::FORMAT_ND, Format::FORMAT_ND); | ||
| 92 | + auto softmaxLseTensor = executor->AllocTensor(DataType::DT_FLOAT, Format::FORMAT_ND, Format::FORMAT_ND); | ||
| 93 | + | ||
| 94 | + // scaleValue is already float type, no need for cast | ||
| 95 | + auto ret = INFER_SHAPE(EagleQuantBlockSparseAttention, | ||
| 96 | + OP_INPUT(query, key, value, blockSparseMaskOptional, attenMaskOptional, | ||
| 97 | + blockShapeOptionalTensor, actualSeqTensor, actualSeqKvTensor, blockTableOptional, | ||
| 98 | + queryScaleOptional, keyScaleOptional, valueScaleOptional), | ||
| 99 | + OP_OUTPUT(attentionOutTensor, softmaxLseTensor), | ||
| 100 | + OP_ATTR(qInputLayout, safeKvInputLayout, | ||
| 101 | + static_cast<int64_t>(numKeyValueHeads), static_cast<int64_t>(maskType), | ||
| 102 | + static_cast<float>(scaleValue), static_cast<int64_t>(innerPrecise), | ||
| 103 | + static_cast<int64_t>(blockSize), static_cast<uint32_t>(preTokens), | ||
| 104 | + static_cast<int64_t>(nextTokens), static_cast<int64_t>(softmaxLseFlag))); | ||
| 105 | + if (ret != ACLNN_SUCCESS) { | ||
| 106 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "EagleQuantBlockSparseAttention infer shape failed, scaleValue: %f.", scaleValue); | ||
| 107 | + return {nullptr, nullptr}; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + ADD_TO_LAUNCHER_LIST_AICORE(EagleQuantBlockSparseAttention, | ||
| 111 | + OP_INPUT(query, key, value, blockSparseMaskOptional, attenMaskOptional, | ||
| 112 | + blockShapeOptionalTensor, actualSeqTensor, actualSeqKvTensor, | ||
| 113 | + blockTableOptional, queryScaleOptional, keyScaleOptional, valueScaleOptional), | ||
| 114 | + OP_OUTPUT(attentionOutTensor, softmaxLseTensor), | ||
| 115 | + OP_ATTR(qInputLayout, safeKvInputLayout, static_cast<int64_t>(numKeyValueHeads), | ||
| 116 | + static_cast<int64_t>(maskType), static_cast<float>(scaleValue), | ||
| 117 | + static_cast<int64_t>(innerPrecise), static_cast<int64_t>(blockSize), | ||
| 118 | + static_cast<int64_t>(preTokens), static_cast<int64_t>(nextTokens), | ||
| 119 | + static_cast<int64_t>(softmaxLseFlag))); | ||
| 120 | + | ||
| 121 | + return {attentionOutTensor, softmaxLseTensor}; | ||
| 122 | +} | ||
| 123 | +} // namespace l0op | ||
| 124 | + | ||
| 125 | + | ||
| @@ -0,0 +1,49 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +namespace l0op { | ||
| 19 | + | ||
| 20 | +const std::array<const aclTensor *, 2> EagleQuantBlockSparseAttention( | ||
| 21 | + const aclTensor *query, | ||
| 22 | + const aclTensor *key, | ||
| 23 | + const aclTensor *value, | ||
| 24 | + const aclTensor *blockSparseMaskOptional, | ||
| 25 | + const aclTensor *attenMaskOptional, | ||
| 26 | + const aclIntArray *blockShapeOptional, | ||
| 27 | + const aclIntArray *actualSeqLengthsOptional, | ||
| 28 | + const aclIntArray *actualSeqLengthsKvOptional, | ||
| 29 | + const aclTensor *blockTableOptional, | ||
| 30 | + const aclTensor *queryScaleOptional, | ||
| 31 | + const aclTensor *keyScaleOptional, | ||
| 32 | + const aclTensor *valueScaleOptional, | ||
| 33 | + const char *qInputLayout, | ||
| 34 | + const char *kvInputLayout, | ||
| 35 | + int64_t numKeyValueHeads, | ||
| 36 | + int64_t maskType, | ||
| 37 | + double scaleValue, | ||
| 38 | + int64_t innerPrecise, | ||
| 39 | + int64_t blockSize, | ||
| 40 | + int64_t preTokens, | ||
| 41 | + int64_t nextTokens, | ||
| 42 | + int64_t softmaxLseFlag, | ||
| 43 | + aclOpExecutor *executor, | ||
| 44 | + op::DataType outDType); | ||
| 45 | + | ||
| 46 | +} // namespace l0op | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + | ||
| @@ -0,0 +1,58 @@ | |||
| 1 | +# Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. | ||
| 2 | +# MindIE is licensed under Mulan PSL v2. | ||
| 3 | +# You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 4 | +# You may obtain a copy of Mulan PSL v2 at: | ||
| 5 | +# http://license.coscl.org.cn/MulanPSL2 | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 7 | +# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 8 | +# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 9 | +# See the Mulan PSL v2 for more details. | ||
| 10 | + | ||
| 11 | +add_ops_compile_options( | ||
| 12 | + OP_NAME EagleQuantBlockSparseAttention | ||
| 13 | + OPTIONS --cce-auto-sync=off | ||
| 14 | + -Wno-deprecated-declarations | ||
| 15 | + -fpermissive | ||
| 16 | +) | ||
| 17 | + | ||
| 18 | +# def.cpp is routed to the "inner" aclnn generator so that opbuild produces | ||
| 19 | +# aclnnInnerEagleQuantBlockSparseAttention and does NOT collide with the | ||
| 20 | +# hand-written public aclnnEagleQuantBlockSparseAttention provided via op_api. | ||
| 21 | +target_sources(op_host_aclnnInner PRIVATE | ||
| 22 | + eagle_quant_block_sparse_attention_def.cpp | ||
| 23 | +) | ||
| 24 | + | ||
| 25 | +target_sources(optiling PRIVATE | ||
| 26 | + eagle_quant_block_sparse_attention_tiling.cpp | ||
| 27 | +) | ||
| 28 | + | ||
| 29 | +if (NOT BUILD_OPEN_PROJECT) | ||
| 30 | + target_sources(opmaster_ct PRIVATE | ||
| 31 | + eagle_quant_block_sparse_attention_tiling.cpp | ||
| 32 | + ) | ||
| 33 | +endif () | ||
| 34 | + | ||
| 35 | +target_sources(opsproto PRIVATE | ||
| 36 | + eagle_quant_block_sparse_attention_infershape.cpp | ||
| 37 | +) | ||
| 38 | + | ||
| 39 | +target_sources(opapi PRIVATE | ||
| 40 | + ${CMAKE_CURRENT_SOURCE_DIR}/../op_api/aclnn_eagle_quant_block_sparse_attention.cpp | ||
| 41 | + ${CMAKE_CURRENT_SOURCE_DIR}/../op_api/eagle_quant_block_sparse_attention.cpp | ||
| 42 | +) | ||
| 43 | + | ||
| 44 | +target_include_directories(optiling PRIVATE | ||
| 45 | + ${CMAKE_CURRENT_SOURCE_DIR} | ||
| 46 | + ${CMAKE_CURRENT_SOURCE_DIR}/.. | ||
| 47 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/inc | ||
| 48 | +) | ||
| 49 | + | ||
| 50 | +target_include_directories(opsproto PRIVATE | ||
| 51 | + ${CMAKE_CURRENT_SOURCE_DIR}/.. | ||
| 52 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/inc | ||
| 53 | +) | ||
| 54 | + | ||
| 55 | +target_include_directories(opapi PRIVATE | ||
| 56 | + ${CMAKE_CURRENT_SOURCE_DIR}/../op_api | ||
| 57 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/inc | ||
| 58 | +) | ||
| @@ -0,0 +1,59 @@ | |||
| 1 | +approvers: | ||
| 2 | +- andylhy | ||
| 3 | +- xiaolong_han | ||
| 4 | +- huxiaobang | ||
| 5 | +- startzgf168 | ||
| 6 | +- huangwei791 | ||
| 7 | +- wangjun-qt | ||
| 8 | +- song-jionghui | ||
| 9 | +- yang-binrong | ||
| 10 | +- jarr0d | ||
| 11 | +- jiang-lirui | ||
| 12 | +- huangli70 | ||
| 13 | +- fzzach | ||
| 14 | +- zhangtj0209 | ||
| 15 | + | ||
| 16 | +reviewers: | ||
| 17 | +- li-xulong | ||
| 18 | +- Allan_Yu | ||
| 19 | +- mabing726 | ||
| 20 | +- miao-fangzheng | ||
| 21 | +- chengsheng304064 | ||
| 22 | +- wangfei6 | ||
| 23 | +- shawn-hu | ||
| 24 | +- li-shengxian | ||
| 25 | +- xig514 | ||
| 26 | +- hilihli | ||
| 27 | +- chen-vvjob | ||
| 28 | +- renkyk | ||
| 29 | +- yang-binrong | ||
| 30 | +- song-jionghui | ||
| 31 | +- wang-zhe123456789 | ||
| 32 | +- huangli70 | ||
| 33 | +- huangwei791 | ||
| 34 | +- shunqi | ||
| 35 | +- wangjun-qt | ||
| 36 | +- jiang-lirui | ||
| 37 | +- realmadrid1016 | ||
| 38 | +- monologue815 | ||
| 39 | +- zhangtj0209 | ||
| 40 | +- GodantShen | ||
| 41 | +- Liexss | ||
| 42 | +- fzzach | ||
| 43 | +- zhanglei_hw | ||
| 44 | +- songkai-huawei | ||
| 45 | +- yangxu19921206 | ||
| 46 | +- crystalhu | ||
| 47 | +- yu-xinjie62 | ||
| 48 | +- zhu-yijun-Julius | ||
| 49 | + | ||
| 50 | +files: | ||
| 51 | + "aclnn_eagle_quant_block_sparse_attention.h": | ||
| 52 | + approvers: | ||
| 53 | + - yinqiande | ||
| 54 | + - miao-fangzheng | ||
| 55 | + "eagle_quant_block_sparse_attention_def.cpp": | ||
| 56 | + approvers: | ||
| 57 | + - yinqiande | ||
| 58 | + - miao-fangzheng | ||
| 59 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_host/eagle_quant_block_sparse_attention_def.cpp+110-0
| @@ -0,0 +1,110 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | +namespace ops { | ||
| 14 | + | ||
| 15 | +class EagleQuantBlockSparseAttention : public OpDef { | ||
| 16 | +public: | ||
| 17 | + explicit EagleQuantBlockSparseAttention(const char* name) : OpDef(name) | ||
| 18 | + { | ||
| 19 | + this->Input("query") | ||
| 20 | + .ParamType(REQUIRED) | ||
| 21 | + .DataType({ge::DT_FLOAT16, ge::DT_BF16, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, | ||
| 22 | + ge::DT_FLOAT16, ge::DT_BF16, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8}) | ||
| 23 | + .FormatList({ge::FORMAT_ND}); | ||
| 24 | + this->Input("key") | ||
| 25 | + .ParamType(REQUIRED) | ||
| 26 | + .DataType({ge::DT_FLOAT16, ge::DT_BF16, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, | ||
| 27 | + ge::DT_FLOAT16, ge::DT_BF16, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8}) | ||
| 28 | + .FormatList({ge::FORMAT_ND}); | ||
| 29 | + this->Input("value") | ||
| 30 | + .ParamType(REQUIRED) | ||
| 31 | + .DataType({ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT8_E4M3FN, ge::DT_INT8, | ||
| 32 | + ge::DT_FLOAT8_E4M3FN, ge::DT_INT8, ge::DT_FLOAT16, ge::DT_BF16, | ||
| 33 | + ge::DT_FLOAT8_E4M3FN, ge::DT_INT8, ge::DT_FLOAT8_E4M3FN, ge::DT_INT8, ge::DT_FLOAT8_E4M3FN, ge::DT_FLOAT8_E4M3FN}) | ||
| 34 | + .FormatList({ge::FORMAT_ND}); | ||
| 35 | + this->Input("blockSparseMask") | ||
| 36 | + .ParamType(OPTIONAL) | ||
| 37 | + .DataType({ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, | ||
| 38 | + ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_BOOL, ge::DT_BOOL}) | ||
| 39 | + .FormatList({ge::FORMAT_ND}); | ||
| 40 | + this->Input("attenMask") | ||
| 41 | + .ParamType(OPTIONAL) | ||
| 42 | + .DataType({ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16, | ||
| 43 | + ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_FLOAT16}) | ||
| 44 | + .FormatList({ge::FORMAT_ND}); | ||
| 45 | + this->Input("blockShape") | ||
| 46 | + .ParamType(OPTIONAL) | ||
| 47 | + .DataType({ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, | ||
| 48 | + ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64}) | ||
| 49 | + .FormatList({ge::FORMAT_ND}); | ||
| 50 | + this->Input("actualSeqLengths") | ||
| 51 | + .ParamType(OPTIONAL) | ||
| 52 | + .DataType({ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, | ||
| 53 | + ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64}) | ||
| 54 | + .FormatList({ge::FORMAT_ND}); | ||
| 55 | + this->Input("actualSeqLengthsKv") | ||
| 56 | + .ParamType(OPTIONAL) | ||
| 57 | + .DataType({ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, | ||
| 58 | + ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64}) | ||
| 59 | + .FormatList({ge::FORMAT_ND}); | ||
| 60 | + this->Input("blockTable") | ||
| 61 | + .ParamType(OPTIONAL) | ||
| 62 | + .DataType({ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, | ||
| 63 | + ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32, ge::DT_INT32}) | ||
| 64 | + .FormatList({ge::FORMAT_ND}); | ||
| 65 | + this->Input("queryScale") | ||
| 66 | + .ParamType(OPTIONAL) | ||
| 67 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, | ||
| 68 | + ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 69 | + .FormatList({ge::FORMAT_ND}); | ||
| 70 | + this->Input("keyScale") | ||
| 71 | + .ParamType(OPTIONAL) | ||
| 72 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, | ||
| 73 | + ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 74 | + .FormatList({ge::FORMAT_ND}); | ||
| 75 | + this->Input("valueScale") | ||
| 76 | + .ParamType(OPTIONAL) | ||
| 77 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, | ||
| 78 | + ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 79 | + .FormatList({ge::FORMAT_ND}); | ||
| 80 | + this->Output("attentionOut") | ||
| 81 | + .ParamType(REQUIRED) | ||
| 82 | + .DataType({ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_BF16, ge::DT_BF16, | ||
| 83 | + ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT16, ge::DT_FLOAT16, ge::DT_BF16, ge::DT_BF16, ge::DT_BF16, ge::DT_FLOAT16}) | ||
| 84 | + .FormatList({ge::FORMAT_ND}); | ||
| 85 | + this->Output("softmaxLse") | ||
| 86 | + .ParamType(OPTIONAL) | ||
| 87 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, | ||
| 88 | + ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 89 | + .FormatList({ge::FORMAT_ND}); | ||
| 90 | + | ||
| 91 | + this->Attr("qInputLayout").AttrType(OPTIONAL).String("TND"); | ||
| 92 | + this->Attr("kvInputLayout").AttrType(OPTIONAL).String("TND"); | ||
| 93 | + this->Attr("numKeyValueHeads").AttrType(OPTIONAL).Int(1); | ||
| 94 | + this->Attr("maskType").AttrType(OPTIONAL).Int(0); | ||
| 95 | + this->Attr("scaleValue").AttrType(OPTIONAL).Float(0.0); | ||
| 96 | + this->Attr("innerPrecise").AttrType(OPTIONAL).Int(0); | ||
| 97 | + this->Attr("blockSize").AttrType(OPTIONAL).Int(0); | ||
| 98 | + this->Attr("preTokens").AttrType(OPTIONAL).Int(2147483647); | ||
| 99 | + this->Attr("nextTokens").AttrType(OPTIONAL).Int(2147483647); | ||
| 100 | + this->Attr("softmaxLseFlag").AttrType(OPTIONAL).Int(0); | ||
| 101 | + | ||
| 102 | + this->AICore().AddConfig("ascend910b"); | ||
| 103 | + this->AICore().AddConfig("ascend910_93"); | ||
| 104 | + this->AICore().AddConfig("ascend950"); | ||
| 105 | + } | ||
| 106 | +}; | ||
| 107 | + | ||
| 108 | +OP_ADD(EagleQuantBlockSparseAttention); | ||
| 109 | + | ||
| 110 | +} // namespace ops | ||
| @@ -0,0 +1,224 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +using namespace ge; | ||
| 17 | + | ||
| 18 | +namespace ops { | ||
| 19 | + | ||
| 20 | +static constexpr uint32_t QUERY_INDEX = 0; | ||
| 21 | +static constexpr uint32_t KEY_INDEX = 1; | ||
| 22 | +static constexpr uint32_t VALUE_INDEX = 2; | ||
| 23 | +static constexpr uint32_t ATTENTION_OUT_INDEX = 0; | ||
| 24 | +static constexpr uint32_t SOFTMAX_LSE_INDEX = 1; | ||
| 25 | + | ||
| 26 | +static constexpr uint32_t ATTR_Q_INPUT_LAYOUT_INDEX = 0; | ||
| 27 | +static constexpr uint32_t ATTR_KV_INPUT_LAYOUT_INDEX = 1; | ||
| 28 | +static constexpr uint32_t ATTR_NUM_KV_HEADS_INDEX = 2; | ||
| 29 | + | ||
| 30 | +static constexpr uint32_t DIM_BSH = 3; | ||
| 31 | +static constexpr uint32_t DIM_TND = 3; | ||
| 32 | +static constexpr uint32_t DIM_BNSD = 4; | ||
| 33 | + | ||
| 34 | +static constexpr uint32_t BSH_DIM_B = 0; | ||
| 35 | +static constexpr uint32_t BSH_DIM_S = 1; | ||
| 36 | +static constexpr uint32_t BSH_DIM_H = 2; | ||
| 37 | + | ||
| 38 | +static constexpr uint32_t TND_DIM_T = 0; | ||
| 39 | +static constexpr uint32_t TND_DIM_N = 1; | ||
| 40 | +static constexpr uint32_t TND_DIM_D = 2; | ||
| 41 | +static constexpr uint32_t TND_DIM_NUM = 3; | ||
| 42 | + | ||
| 43 | +static constexpr uint32_t BNSD_DIM_B = 0; | ||
| 44 | +static constexpr uint32_t BNSD_DIM_N = 1; | ||
| 45 | +static constexpr uint32_t BNSD_DIM_S = 2; | ||
| 46 | +static constexpr uint32_t BNSD_DIM_D = 3; | ||
| 47 | +static constexpr uint32_t BNSD_DIM_NUM = 4; | ||
| 48 | +static constexpr uint32_t LSE_DIM_D = 1; | ||
| 49 | + | ||
| 50 | +static constexpr int32_t UNKNOWN_DIMS = -2; | ||
| 51 | + | ||
| 52 | +static ge::graphStatus InferShapeEagleQuantBlockSparseAttention(gert::InferShapeContext *context) | ||
| 53 | +{ | ||
| 54 | + if (context == nullptr) { | ||
| 55 | + OP_LOGE("EagleQuantBlockSparseAttention", "context is nullptr!"); | ||
| 56 | + return ge::GRAPH_FAILED; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + OP_LOGD(context->GetNodeName(), "Enter EagleQuantBlockSparseAttention InferShape impl."); | ||
| 60 | + | ||
| 61 | + // 获取Query shape | ||
| 62 | + const gert::Shape *queryShape = context->GetInputShape(QUERY_INDEX); | ||
| 63 | + OP_CHECK_NULL_WITH_CONTEXT(context, queryShape); | ||
| 64 | + | ||
| 65 | + // 获取Key shape | ||
| 66 | + const gert::Shape *keyShape = context->GetInputShape(KEY_INDEX); | ||
| 67 | + OP_CHECK_NULL_WITH_CONTEXT(context, keyShape); | ||
| 68 | + | ||
| 69 | + // 获取Value shape | ||
| 70 | + const gert::Shape *valueShape = context->GetInputShape(VALUE_INDEX); | ||
| 71 | + OP_CHECK_NULL_WITH_CONTEXT(context, valueShape); | ||
| 72 | + | ||
| 73 | + // 获取输出shape | ||
| 74 | + gert::Shape *attentionOutShape = context->GetOutputShape(ATTENTION_OUT_INDEX); | ||
| 75 | + OP_CHECK_NULL_WITH_CONTEXT(context, attentionOutShape); | ||
| 76 | + | ||
| 77 | + gert::Shape *softmaxLseShape = context->GetOutputShape(SOFTMAX_LSE_INDEX); | ||
| 78 | + OP_CHECK_NULL_WITH_CONTEXT(context, softmaxLseShape); | ||
| 79 | + | ||
| 80 | + // 获取属性 | ||
| 81 | + auto attrs = context->GetAttrs(); | ||
| 82 | + OP_CHECK_NULL_WITH_CONTEXT(context, attrs); | ||
| 83 | + | ||
| 84 | + const char *qInputLayoutPtr = attrs->GetAttrPointer<char>(ATTR_Q_INPUT_LAYOUT_INDEX); | ||
| 85 | + OP_CHECK_NULL_WITH_CONTEXT(context, qInputLayoutPtr); | ||
| 86 | + | ||
| 87 | + const char *kvInputLayoutPtr = attrs->GetAttrPointer<char>(ATTR_KV_INPUT_LAYOUT_INDEX); | ||
| 88 | + OP_CHECK_NULL_WITH_CONTEXT(context, kvInputLayoutPtr); | ||
| 89 | + | ||
| 90 | + const int64_t *numKvHeadsPtr = attrs->GetInt(ATTR_NUM_KV_HEADS_INDEX); | ||
| 91 | + OP_CHECK_NULL_WITH_CONTEXT(context, numKvHeadsPtr); | ||
| 92 | + | ||
| 93 | + // UNKNOWN DIM处理 | ||
| 94 | + if ((queryShape->GetDimNum() == 1 && queryShape->GetDim(0) == UNKNOWN_DIMS) || | ||
| 95 | + (keyShape->GetDimNum() == 1 && keyShape->GetDim(0) == UNKNOWN_DIMS) || | ||
| 96 | + (valueShape->GetDimNum() == 1 && valueShape->GetDim(0) == UNKNOWN_DIMS)) { | ||
| 97 | + attentionOutShape->SetDimNum(1); | ||
| 98 | + (*attentionOutShape)[0] = UNKNOWN_DIMS; | ||
| 99 | + softmaxLseShape->SetDimNum(1); | ||
| 100 | + (*softmaxLseShape)[0] = UNKNOWN_DIMS; | ||
| 101 | + return ge::GRAPH_SUCCESS; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + // 设置AttentionOut shape (与Query shape相同) | ||
| 105 | + *attentionOutShape = *queryShape; | ||
| 106 | + | ||
| 107 | + // 验证Q layout和KV layout | ||
| 108 | + std::string qLayout(qInputLayoutPtr); | ||
| 109 | + std::string kvLayout(kvInputLayoutPtr); | ||
| 110 | + | ||
| 111 | + // 验证Q layout (只支持TND和BNSD) | ||
| 112 | + if (qLayout == "TND") { | ||
| 113 | + if (queryShape->GetDimNum() != DIM_TND) { | ||
| 114 | + OP_LOGE(context->GetNodeName(), "Layout TND, queryDims(%zu) must be 3!", queryShape->GetDimNum()); | ||
| 115 | + return ge::GRAPH_FAILED; | ||
| 116 | + } | ||
| 117 | + } else if (qLayout == "BNSD") { | ||
| 118 | + if (queryShape->GetDimNum() != DIM_BNSD) { | ||
| 119 | + OP_LOGE(context->GetNodeName(), "Layout BNSD, queryDims(%zu) must be 4!", queryShape->GetDimNum()); | ||
| 120 | + return ge::GRAPH_FAILED; | ||
| 121 | + } | ||
| 122 | + } else { | ||
| 123 | + OP_LOGE(context->GetNodeName(), "Unsupported Q layout: %s. Only TND and BNSD are supported.", qInputLayoutPtr); | ||
| 124 | + return ge::GRAPH_FAILED; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + // 验证Q和KV格式一致性:如果其中一个是BNSD,另一个也必须是BNSD | ||
| 128 | + bool isQBNSD = (qLayout == "BNSD"); | ||
| 129 | + bool isKvBNSD = (kvLayout == "BNSD"); | ||
| 130 | + | ||
| 131 | + if (isQBNSD != isKvBNSD) { | ||
| 132 | + OP_LOGE(context->GetNodeName(), | ||
| 133 | + "Q and KV layouts must match: if one is BNSD, the other must also be BNSD. " | ||
| 134 | + "Q layout: %s, KV layout: %s", qLayout.c_str(), kvLayout.c_str()); | ||
| 135 | + return ge::GRAPH_FAILED; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + // 验证KV layout | ||
| 139 | + if (kvLayout == "TND") { | ||
| 140 | + if (keyShape->GetDimNum() != DIM_TND || valueShape->GetDimNum() != DIM_TND) { | ||
| 141 | + OP_LOGE(context->GetNodeName(), "Layout TND, KV dims must be 3!"); | ||
| 142 | + return ge::GRAPH_FAILED; | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + // TND格式: [T, N, D] | ||
| 146 | + int64_t kvN = keyShape->GetDim(TND_DIM_N); | ||
| 147 | + int64_t kvD = keyShape->GetDim(TND_DIM_D); | ||
| 148 | + | ||
| 149 | + if (*numKvHeadsPtr != 0 && kvN != *numKvHeadsPtr) { | ||
| 150 | + OP_LOGE(context->GetNodeName(), "KV heads mismatch in TND format: %ld != %ld", kvN, *numKvHeadsPtr); | ||
| 151 | + return ge::GRAPH_FAILED; | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + if (valueShape->GetDim(TND_DIM_D) != kvD) { | ||
| 155 | + OP_LOGE(context->GetNodeName(), "K and V head dimension mismatch in TND format"); | ||
| 156 | + return ge::GRAPH_FAILED; | ||
| 157 | + } | ||
| 158 | + } else if (kvLayout == "BNSD") { | ||
| 159 | + if (keyShape->GetDimNum() != DIM_BNSD || valueShape->GetDimNum() != DIM_BNSD) { | ||
| 160 | + OP_LOGE(context->GetNodeName(), "Layout BNSD, KV dims must be 4!"); | ||
| 161 | + return ge::GRAPH_FAILED; | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + // BNSD格式: [B, N, S, D] | ||
| 165 | + int64_t kvB = keyShape->GetDim(BNSD_DIM_B); | ||
| 166 | + int64_t kvN = keyShape->GetDim(BNSD_DIM_N); | ||
| 167 | + int64_t kvD = keyShape->GetDim(BNSD_DIM_D); | ||
| 168 | + | ||
| 169 | + if (*numKvHeadsPtr != 0 && kvN != *numKvHeadsPtr) { | ||
| 170 | + OP_LOGE(context->GetNodeName(), "KV heads mismatch in BNSD format: %ld != %ld", kvN, *numKvHeadsPtr); | ||
| 171 | + return ge::GRAPH_FAILED; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + if (valueShape->GetDim(BNSD_DIM_D) != kvD) { | ||
| 175 | + OP_LOGE(context->GetNodeName(), "K and V head dimension mismatch in BNSD format"); | ||
| 176 | + return ge::GRAPH_FAILED; | ||
| 177 | + } | ||
| 178 | + } else { | ||
| 179 | + OP_LOGE(context->GetNodeName(), "Unsupported KV layout: %s. Only TND format is supported.", kvInputLayoutPtr); | ||
| 180 | + return ge::GRAPH_FAILED; | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + // 设置SoftmaxLse shape (如果需要) | ||
| 184 | + // SoftmaxLse shape通常是 [batch, num_heads, q_seqlen, 1] 或类似维度 | ||
| 185 | + if (qLayout == "TND") { | ||
| 186 | + // TND格式 | ||
| 187 | + softmaxLseShape->SetDimNum(TND_DIM_NUM); | ||
| 188 | + (*softmaxLseShape)[TND_DIM_T] = queryShape->GetDim(TND_DIM_T); | ||
| 189 | + (*softmaxLseShape)[TND_DIM_N] = queryShape->GetDim(TND_DIM_N); | ||
| 190 | + (*softmaxLseShape)[TND_DIM_D] = LSE_DIM_D; | ||
| 191 | + } else if (qLayout == "BNSD") { | ||
| 192 | + // BNSD格式 | ||
| 193 | + softmaxLseShape->SetDimNum(BNSD_DIM_NUM); | ||
| 194 | + (*softmaxLseShape)[BNSD_DIM_B] = queryShape->GetDim(BNSD_DIM_B); | ||
| 195 | + (*softmaxLseShape)[BNSD_DIM_N] = queryShape->GetDim(BNSD_DIM_N); | ||
| 196 | + (*softmaxLseShape)[BNSD_DIM_S] = queryShape->GetDim(BNSD_DIM_S); | ||
| 197 | + (*softmaxLseShape)[BNSD_DIM_D] = LSE_DIM_D; | ||
| 198 | + } else { | ||
| 199 | + OP_LOGE(context->GetNodeName(), "Unexpected Q layout in softmaxLse shape calculation: %s", qInputLayoutPtr); | ||
| 200 | + return ge::GRAPH_FAILED; | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + OP_LOGD(context->GetNodeName(), "EagleQuantBlockSparseAttention InferShape success."); | ||
| 204 | + return ge::GRAPH_SUCCESS; | ||
| 205 | +} | ||
| 206 | + | ||
| 207 | +ge::graphStatus InferDataTypeEagleQuantBlockSparseAttention(gert::InferDataTypeContext *context) | ||
| 208 | +{ | ||
| 209 | + if (context == nullptr) { | ||
| 210 | + return ge::GRAPH_FAILED; | ||
| 211 | + } | ||
| 212 | + auto dtype = context->GetInputDataType(0); | ||
| 213 | + context->SetOutputDataType(0, dtype); | ||
| 214 | + context->SetOutputDataType(1, DT_FLOAT); | ||
| 215 | + | ||
| 216 | + return GRAPH_SUCCESS; | ||
| 217 | +} | ||
| 218 | + | ||
| 219 | +IMPL_OP_INFERSHAPE(EagleQuantBlockSparseAttention) | ||
| 220 | + .InferShape(InferShapeEagleQuantBlockSparseAttention) | ||
| 221 | + .InferDataType(InferDataTypeEagleQuantBlockSparseAttention); | ||
| 222 | + | ||
| 223 | +} // namespace ops | ||
| 224 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_host/eagle_quant_block_sparse_attention_tiling.cpp+1018-0
| @@ -0,0 +1,1018 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +using namespace ge; | ||
| 26 | +using namespace std; | ||
| 27 | + | ||
| 28 | +constexpr int TND_DIM_T = 0; | ||
| 29 | +constexpr int TND_DIM_N = 1; | ||
| 30 | +constexpr int TND_DIM_D = 2; | ||
| 31 | +constexpr int TND_DIM_NUM = 3; | ||
| 32 | + | ||
| 33 | +constexpr int BNSD_DIM_B = 0; | ||
| 34 | +constexpr int BNSD_DIM_N = 1; | ||
| 35 | +constexpr int BNSD_DIM_S = 2; | ||
| 36 | +constexpr int BNSD_DIM_D = 3; | ||
| 37 | +constexpr int BNSD_DIM_NUM = 4; | ||
| 38 | + | ||
| 39 | +constexpr int BSH_DIM_B = 0; | ||
| 40 | +constexpr int BSH_DIM_S = 1; | ||
| 41 | +constexpr int BSH_DIM_H = 2; | ||
| 42 | + | ||
| 43 | +constexpr int QUERY_INDEX = 0; | ||
| 44 | +constexpr int KEY_INDEX = 1; | ||
| 45 | +constexpr int VALUE_INDEX = 2; | ||
| 46 | +constexpr int BLOCK_SPARSE_MASK_INDEX = 3; | ||
| 47 | +constexpr int ATTEN_MASK_INDEX = 4; | ||
| 48 | +constexpr int BLOCK_SHAPE_INDEX = 5; | ||
| 49 | +constexpr int ACTUAL_SEQ_LENGTHS_INDEX = 6; | ||
| 50 | +constexpr int ACTUAL_SEQ_LENGTHS_KV_INDEX = 7; | ||
| 51 | +constexpr int BLOCK_TABLE_INDEX = 8; | ||
| 52 | +constexpr int SOFTMAX_LSE_INDEX = 10; | ||
| 53 | +constexpr int MAX_BLOCK_NUM_INDEX = 2; | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +constexpr int Q_INPUT_LAYOUT_INDEX = 0; | ||
| 57 | +constexpr int KV_INPUT_LAYOUT_INDEX = 1; | ||
| 58 | +constexpr int NUM_KEY_VALUE_HEADS_INDEX = 2; | ||
| 59 | +constexpr int MASK_TYPE_INDEX = 3; | ||
| 60 | +constexpr int SCALE_VALUE_INDEX = 4; | ||
| 61 | +constexpr int INNER_PRECISE_INDEX = 5; | ||
| 62 | +constexpr int BLOCK_SIZE_INDEX = 6; | ||
| 63 | +constexpr int PRE_TOKENS_INDEX = 7; | ||
| 64 | +constexpr int NEXT_TOKENS_INDEX = 8; | ||
| 65 | +constexpr int SOFTMAX_LSE_FLAG_INDEX = 9; | ||
| 66 | + | ||
| 67 | +constexpr int VALID_EMBEDDING_SIZE_64 = 64; | ||
| 68 | +constexpr int VALID_EMBEDDING_SIZE_128 = 128; | ||
| 69 | + | ||
| 70 | +constexpr int LSE_NO_OUT = 0; | ||
| 71 | +constexpr int LSE_OUT = 1; | ||
| 72 | + | ||
| 73 | +namespace optiling { | ||
| 74 | + | ||
| 75 | +constexpr uint32_t BASIC_BLOCK_SIZE = 128; | ||
| 76 | +constexpr uint32_t WORKSPACE_BLOCK_SIZE_DB = 131072; | ||
| 77 | +constexpr uint32_t NUM3 = 3; | ||
| 78 | +constexpr uint32_t SOC_VER_950_CODE = 4; | ||
| 79 | +constexpr uint32_t INF_WINDOW_SIZE_PRE_NEXT = 2147483647; | ||
| 80 | +constexpr uint32_t SPARSE_PATTERN_MODE_MASK = 0; | ||
| 81 | +constexpr uint32_t SPARSE_PATTERN_MODE_TABLE = 1; | ||
| 82 | + | ||
| 83 | +constexpr uint32_t TILE_SIZE_128 = 128; | ||
| 84 | +constexpr uint32_t TILE_SIZE_256 = 256; | ||
| 85 | +constexpr uint32_t TILE_SIZE_512 = 512; | ||
| 86 | +constexpr uint32_t D_SIZE_128 = 128; | ||
| 87 | +constexpr uint32_t D_SIZE_256 = 256; | ||
| 88 | + | ||
| 89 | +constexpr uint32_t SOLO_BUF = 1; | ||
| 90 | +constexpr uint32_t DUO_BUF = 2; | ||
| 91 | +constexpr uint32_t TRIO_BUF = 3; | ||
| 92 | + | ||
| 93 | +std::unordered_map<std::string, std::string> inputLayoutMapQ2Kv = { | ||
| 94 | + {"TND", "TND"}, | ||
| 95 | + {"BNSD", "BNSD"} | ||
| 96 | +}; | ||
| 97 | + | ||
| 98 | +static inline uint32_t CeilDiv(uint32_t n1, uint32_t n2) | ||
| 99 | +{ | ||
| 100 | + if (n1 == 0) { | ||
| 101 | + return 0; | ||
| 102 | + } | ||
| 103 | + return (n2 != 0) ? ((n1 + n2 - 1) / n2) : n1; | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +static inline uint32_t GetQBlocks(int32_t qseqlen, int32_t x) | ||
| 107 | +{ | ||
| 108 | + uint32_t qBlocksInX = CeilDiv(x, BASIC_BLOCK_SIZE); | ||
| 109 | + uint32_t completeXBlocks = x != 0 ? qseqlen / x : qseqlen / BASIC_BLOCK_SIZE; | ||
| 110 | + uint32_t remainingSeqlen = x != 0 ? qseqlen - completeXBlocks * x : qseqlen % BASIC_BLOCK_SIZE; | ||
| 111 | + uint32_t remainingBlocks = CeilDiv(remainingSeqlen, BASIC_BLOCK_SIZE); | ||
| 112 | + return qBlocksInX * completeXBlocks + remainingBlocks; | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +static inline uint32_t GetQNBlockTile() | ||
| 116 | +{ | ||
| 117 | + uint32_t qNBlockTile = 1; | ||
| 118 | + return qNBlockTile; | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +ge::graphStatus BSATiling::GetNpuInfo(gert::TilingContext *bsaContext) | ||
| 122 | +{ | ||
| 123 | + auto ascendcPlatform = platform_ascendc::PlatformAscendC(bsaContext->GetPlatformInfo()); | ||
| 124 | + | ||
| 125 | + ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ubSize_); | ||
| 126 | + libapiSize_ = ascendcPlatform.GetLibApiWorkSpaceSize(); | ||
| 127 | + aivNum_ = ascendcPlatform.GetCoreNumAiv(); | ||
| 128 | + aicNum_ = ascendcPlatform.GetCoreNumAic(); | ||
| 129 | + socVer_ = static_cast<uint32_t>(ascendcPlatform.GetSocVersion()); | ||
| 130 | + return ge::GRAPH_SUCCESS; | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +ge::graphStatus BSATiling::ValidateTNDSeqlenSum(gert::TilingContext *bsaContext) | ||
| 134 | +{ | ||
| 135 | + // 只在TND格式时进行校验 | ||
| 136 | + if (qInputLayout_ != RFAQInputLayout::TND_Q || kvCacheLayout_ != RFAKvCacheLayout::TND) { | ||
| 137 | + return ge::GRAPH_SUCCESS; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + // 计算所有batch的qseqlen之和 | ||
| 141 | + int64_t sumQSeqlen = 0; | ||
| 142 | + int64_t sumKvSeqlen = 0; | ||
| 143 | + | ||
| 144 | + for (uint32_t i = 0; i < batch_; i++) { | ||
| 145 | + sumQSeqlen += qSeqLenList_[i]; | ||
| 146 | + sumKvSeqlen += kvSeqLenList_[i]; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + // 校验qseqlen之和是否等于Q的T | ||
| 150 | + if (sumQSeqlen != totalTokensT_) { | ||
| 151 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 152 | + "TND format validation failed: sum of qseqlen across all batches (%ld) != Q T (%ld)", | ||
| 153 | + sumQSeqlen, totalTokensT_); | ||
| 154 | + return ge::GRAPH_FAILED; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + // 校验kvseqlen之和是否等于KV的T | ||
| 158 | + if (sumKvSeqlen != totalTokensKv_) { | ||
| 159 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 160 | + "TND format validation failed: sum of kvseqlen across all batches (%ld) != KV T (%ld)", | ||
| 161 | + sumKvSeqlen, totalTokensKv_); | ||
| 162 | + return ge::GRAPH_FAILED; | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + return ge::GRAPH_SUCCESS; | ||
| 166 | +} | ||
| 167 | + | ||
| 168 | +ge::graphStatus BSATiling::GetInputLayout(gert::TilingContext *bsaContext) | ||
| 169 | +{ | ||
| 170 | + auto attrs = bsaContext->GetAttrs(); | ||
| 171 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, attrs); | ||
| 172 | + auto attrLayoutQ = attrs->GetAttrPointer<char>(Q_INPUT_LAYOUT_INDEX); | ||
| 173 | + auto attrLayoutKv = attrs->GetAttrPointer<char>(KV_INPUT_LAYOUT_INDEX); | ||
| 174 | + if (attrLayoutQ == nullptr || attrLayoutKv == nullptr) { | ||
| 175 | + OP_LOGE(bsaContext->GetNodeName(), "qInputLayout, kvInputLayout must be provided."); | ||
| 176 | + return ge::GRAPH_FAILED; | ||
| 177 | + } | ||
| 178 | + std::string qLayout(attrLayoutQ); | ||
| 179 | + std::string kvLayout(attrLayoutKv); | ||
| 180 | + auto it = inputLayoutMapQ2Kv.find(qLayout); | ||
| 181 | + auto itRev = inputLayoutMapQ2Kv.find(kvLayout); | ||
| 182 | + if (it == inputLayoutMapQ2Kv.end() || itRev == inputLayoutMapQ2Kv.end()) { | ||
| 183 | + OP_LOGE(bsaContext->GetNodeName(), "The inputLayout attrs only support TND/BNSD."); | ||
| 184 | + return ge::GRAPH_FAILED; | ||
| 185 | + } else if (it->second != kvLayout) { | ||
| 186 | + OP_LOGE(bsaContext->GetNodeName(), "QInputLayout and kvInputLayout must be the same."); | ||
| 187 | + return ge::GRAPH_FAILED; | ||
| 188 | + } else if (it->first == "TND") { | ||
| 189 | + qInputLayout_ = RFAQInputLayout::TND_Q; | ||
| 190 | + kvCacheLayout_ = RFAKvCacheLayout::TND; | ||
| 191 | + } else if (it->first == "BNSD") { | ||
| 192 | + qInputLayout_ = RFAQInputLayout::BNSD_Q; | ||
| 193 | + kvCacheLayout_ = RFAKvCacheLayout::BNSD; | ||
| 194 | + } | ||
| 195 | + return ge::GRAPH_SUCCESS; | ||
| 196 | +} | ||
| 197 | + | ||
| 198 | +ge::graphStatus BSATiling::CheckQKVDtype(gert::TilingContext *bsaContext) | ||
| 199 | +{ | ||
| 200 | + auto qInputDesc = bsaContext->GetInputDesc(QUERY_INDEX); | ||
| 201 | + auto kInputDesc = bsaContext->GetInputDesc(KEY_INDEX); | ||
| 202 | + auto vInputDesc = bsaContext->GetInputDesc(VALUE_INDEX); | ||
| 203 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, qInputDesc); | ||
| 204 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, kInputDesc); | ||
| 205 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, vInputDesc); | ||
| 206 | + dataType_ = qInputDesc->GetDataType(); | ||
| 207 | + auto kDataType = kInputDesc->GetDataType(); | ||
| 208 | + vDataType_ = vInputDesc->GetDataType(); | ||
| 209 | + | ||
| 210 | + // 原有FP16/BF16校验保留 | ||
| 211 | + if (dataType_ != ge::DT_FLOAT16 && dataType_ != ge::DT_BF16 && dataType_ != ge::DT_INT8) { | ||
| 212 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 213 | + "The supported dtype of query/key is float16, bfloat16 or int8."); | ||
| 214 | + return ge::GRAPH_FAILED; | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + // 950 混合精度特判:Q/K=int8, V=FLOAT8_E4M3FN | ||
| 218 | + if (socVer_ == SOC_VER_950_CODE && | ||
| 219 | + dataType_ == ge::DT_INT8 && | ||
| 220 | + kDataType == ge::DT_INT8 ) { | ||
| 221 | + return ge::GRAPH_SUCCESS; | ||
| 222 | + } else if (dataType_ != kDataType || dataType_ != vDataType_) { | ||
| 223 | + // 非混合精度场景保持原有严格一致性校验 | ||
| 224 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 225 | + "Tensor query/key/value must have consistent dtype, or use 950 mixed prec (Q/K=int8, V=fp8)."); | ||
| 226 | + return ge::GRAPH_FAILED; | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + return ge::GRAPH_SUCCESS; | ||
| 230 | +} | ||
| 231 | + | ||
| 232 | +ge::graphStatus BSATiling::CheckQKVDimVal( | ||
| 233 | + gert::TilingContext *bsaContext, uint32_t kHeads, uint32_t vHeads, uint32_t kHeadDim, uint32_t vHeadDim) | ||
| 234 | +{ | ||
| 235 | + if (embeddingSize_ != kHeadDim || embeddingSize_ != vHeadDim) { | ||
| 236 | + OP_LOGE(bsaContext->GetNodeName(), "Tensor query/key/value must have consistent headDim with each other, " | ||
| 237 | + "but got qHeadDim %u, kHeadDim %u, vHeadDim %u.", embeddingSize_, kHeadDim, vHeadDim); | ||
| 238 | + return ge::GRAPH_FAILED; | ||
| 239 | + } | ||
| 240 | + if (kvHeads_ != kHeads || kvHeads_ != vHeads) { | ||
| 241 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 242 | + "Tensor key/value must have consistent headNum with each other and attr kvHeads, " | ||
| 243 | + "but got kHeads %u, vHeads %u, kvHeads(attr) %u.", kHeads, vHeads, kvHeads_); | ||
| 244 | + return ge::GRAPH_FAILED; | ||
| 245 | + } | ||
| 246 | + // temporary regulations of D | ||
| 247 | + if ((embeddingSize_ != VALID_EMBEDDING_SIZE_128) && (embeddingSize_ != VALID_EMBEDDING_SIZE_64)) { | ||
| 248 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 249 | + "The supported headDim so far is 64 or 128, but got %u.", embeddingSize_); | ||
| 250 | + return ge::GRAPH_FAILED; | ||
| 251 | + } | ||
| 252 | + return ge::GRAPH_SUCCESS; | ||
| 253 | +} | ||
| 254 | + | ||
| 255 | +ge::graphStatus BSATiling::ParseQKVInTND(gert::TilingContext *bsaContext) | ||
| 256 | +{ | ||
| 257 | + const auto *queryShape = bsaContext->GetInputShape(QUERY_INDEX); | ||
| 258 | + const auto *keyShape = bsaContext->GetInputShape(KEY_INDEX); | ||
| 259 | + const auto *valueShape = bsaContext->GetInputShape(VALUE_INDEX); | ||
| 260 | + if (queryShape == nullptr || keyShape == nullptr || valueShape == nullptr) { | ||
| 261 | + OP_LOGE(bsaContext->GetNodeName(), "Query/Key/Value shape is null"); | ||
| 262 | + return ge::GRAPH_FAILED; | ||
| 263 | + } | ||
| 264 | + if (queryShape->GetStorageShape().GetDimNum() != TND_DIM_NUM || | ||
| 265 | + keyShape->GetStorageShape().GetDimNum() != TND_DIM_NUM || | ||
| 266 | + valueShape->GetStorageShape().GetDimNum() != TND_DIM_NUM) { | ||
| 267 | + OP_LOGE(bsaContext->GetNodeName(), "Tensor query/key/value must have 3 dimensions when layout is 'TND'."); | ||
| 268 | + return ge::GRAPH_FAILED; | ||
| 269 | + } | ||
| 270 | + totalTokensT_ = queryShape->GetStorageShape().GetDim(TND_DIM_T); | ||
| 271 | + totalTokensKv_ = keyShape->GetStorageShape().GetDim(TND_DIM_T); | ||
| 272 | + numHeads_ = static_cast<uint32_t>(queryShape->GetStorageShape().GetDim(TND_DIM_N)); | ||
| 273 | + auto kHeads = static_cast<uint32_t>(keyShape->GetStorageShape().GetDim(TND_DIM_N)); | ||
| 274 | + auto vHeads = static_cast<uint32_t>(valueShape->GetStorageShape().GetDim(TND_DIM_N)); | ||
| 275 | + embeddingSize_ = static_cast<uint32_t>(queryShape->GetStorageShape().GetDim(TND_DIM_D)); | ||
| 276 | + auto embeddingSizeK = static_cast<uint32_t>(keyShape->GetStorageShape().GetDim(TND_DIM_D)); | ||
| 277 | + auto embeddingSizeV = static_cast<uint32_t>(valueShape->GetStorageShape().GetDim(TND_DIM_D)); | ||
| 278 | + if (CheckQKVDimVal(bsaContext, kHeads, vHeads, embeddingSizeK, embeddingSizeV) != ge::GRAPH_SUCCESS) { | ||
| 279 | + OP_LOGE(bsaContext->GetNodeName(), "Check query/key/value dim values failed."); | ||
| 280 | + return ge::GRAPH_FAILED; | ||
| 281 | + } | ||
| 282 | + return ge::GRAPH_SUCCESS; | ||
| 283 | +} | ||
| 284 | + | ||
| 285 | +ge::graphStatus BSATiling::ParseQKVInBNSD(gert::TilingContext *bsaContext) | ||
| 286 | +{ | ||
| 287 | + const auto *queryShape = bsaContext->GetInputShape(QUERY_INDEX); | ||
| 288 | + const auto *keyShape = bsaContext->GetInputShape(KEY_INDEX); | ||
| 289 | + const auto *valueShape = bsaContext->GetInputShape(VALUE_INDEX); | ||
| 290 | + if (queryShape == nullptr || keyShape == nullptr || valueShape == nullptr) { | ||
| 291 | + OP_LOGE(bsaContext->GetNodeName(), "Query/Key/Value shape is null"); | ||
| 292 | + return ge::GRAPH_FAILED; | ||
| 293 | + } | ||
| 294 | + if (queryShape->GetStorageShape().GetDimNum() != BNSD_DIM_NUM || | ||
| 295 | + keyShape->GetStorageShape().GetDimNum() != BNSD_DIM_NUM || | ||
| 296 | + valueShape->GetStorageShape().GetDimNum() != BNSD_DIM_NUM) { | ||
| 297 | + OP_LOGE(bsaContext->GetNodeName(), "Tensor query/key/value must have 4 dimensions when layout is 'BNSD'."); | ||
| 298 | + return ge::GRAPH_FAILED; | ||
| 299 | + } | ||
| 300 | + batch_ = static_cast<uint32_t>(queryShape->GetStorageShape().GetDim(BNSD_DIM_B)); | ||
| 301 | + auto kBatch = static_cast<uint32_t>(keyShape->GetStorageShape().GetDim(BNSD_DIM_B)); | ||
| 302 | + auto vBatch = static_cast<uint32_t>(valueShape->GetStorageShape().GetDim(BNSD_DIM_B)); | ||
| 303 | + numHeads_ = static_cast<uint32_t>(queryShape->GetStorageShape().GetDim(BNSD_DIM_N)); | ||
| 304 | + auto kHeads = static_cast<uint32_t>(keyShape->GetStorageShape().GetDim(BNSD_DIM_N)); | ||
| 305 | + auto vHeads = static_cast<uint32_t>(valueShape->GetStorageShape().GetDim(BNSD_DIM_N)); | ||
| 306 | + embeddingSize_ = static_cast<uint32_t>(queryShape->GetStorageShape().GetDim(BNSD_DIM_D)); | ||
| 307 | + auto embeddingSizeK = static_cast<uint32_t>(keyShape->GetStorageShape().GetDim(BNSD_DIM_D)); | ||
| 308 | + auto embeddingSizeV = static_cast<uint32_t>(valueShape->GetStorageShape().GetDim(BNSD_DIM_D)); | ||
| 309 | + maxQSeqlen_ = static_cast<uint32_t>(queryShape->GetStorageShape().GetDim(BNSD_DIM_S)); | ||
| 310 | + maxKvSeqlen_ = static_cast<uint32_t>(keyShape->GetStorageShape().GetDim(BNSD_DIM_S)); | ||
| 311 | + if (batch_ != kBatch || batch_ != vBatch) { | ||
| 312 | + OP_LOGE(bsaContext->GetNodeName(), "Tensor query/key/value must have consistent batch with each other, " | ||
| 313 | + "but got qBatch %u, kBatch %u, vBatch %u.", batch_, kBatch, vBatch); | ||
| 314 | + return ge::GRAPH_FAILED; | ||
| 315 | + } | ||
| 316 | + if (CheckQKVDimVal(bsaContext, kHeads, vHeads, embeddingSizeK, embeddingSizeV) != ge::GRAPH_SUCCESS) { | ||
| 317 | + OP_LOGE(bsaContext->GetNodeName(), "Check query/key/value dim values failed."); | ||
| 318 | + return ge::GRAPH_FAILED; | ||
| 319 | + } | ||
| 320 | + return ge::GRAPH_SUCCESS; | ||
| 321 | +} | ||
| 322 | + | ||
| 323 | +ge::graphStatus BSATiling::ParseRequiredTensors(gert::TilingContext *bsaContext) | ||
| 324 | +{ | ||
| 325 | + if (CheckQKVDtype(bsaContext) != ge::GRAPH_SUCCESS) { | ||
| 326 | + return ge::GRAPH_FAILED; | ||
| 327 | + } | ||
| 328 | + ge::graphStatus ret = ge::GRAPH_SUCCESS; | ||
| 329 | + if (qInputLayout_ == RFAQInputLayout::TND_Q) { | ||
| 330 | + ret = ParseQKVInTND(bsaContext); | ||
| 331 | + } else if (qInputLayout_ == RFAQInputLayout::BNSD_Q) { | ||
| 332 | + ret = ParseQKVInBNSD(bsaContext); | ||
| 333 | + } | ||
| 334 | + return ret; | ||
| 335 | +} | ||
| 336 | + | ||
| 337 | +ge::graphStatus BSATiling::ParseSeqlensInTND(gert::TilingContext *bsaContext) | ||
| 338 | +{ | ||
| 339 | + const auto *actualSeqLengths = bsaContext->GetOptionalInputTensor(ACTUAL_SEQ_LENGTHS_INDEX); | ||
| 340 | + const auto *actualSeqLengthsKv = bsaContext->GetOptionalInputTensor(ACTUAL_SEQ_LENGTHS_KV_INDEX); | ||
| 341 | + if (actualSeqLengths == nullptr || actualSeqLengthsKv == nullptr) { | ||
| 342 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 343 | + "ActualSeqLengths/actualSeqLengthsKv must be provided when corresponding layout is 'TND'."); | ||
| 344 | + return ge::GRAPH_FAILED; | ||
| 345 | + } | ||
| 346 | + batch_ = static_cast<uint32_t>(actualSeqLengths->GetShapeSize()); | ||
| 347 | + auto batchKvS = static_cast<uint32_t>(actualSeqLengthsKv->GetShapeSize()); | ||
| 348 | + if (batch_ != batchKvS) { | ||
| 349 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 350 | + "ActualSeqLengths & actualSeqLengthsKv must have consistent batch size, " | ||
| 351 | + "but got batch in actualSeqLengths: %u, batch in actualSeqLengthsKv: %u", batch_, batchKvS); | ||
| 352 | + return ge::GRAPH_FAILED; | ||
| 353 | + } | ||
| 354 | + qSeqLenList_ = actualSeqLengths->GetData<int64_t>(); | ||
| 355 | + kvSeqLenList_ = actualSeqLengthsKv->GetData<int64_t>(); | ||
| 356 | + useUniformQSeqlen_ = false; | ||
| 357 | + useUniformKvSeqlen_ = false; | ||
| 358 | + return ge::GRAPH_SUCCESS; | ||
| 359 | +} | ||
| 360 | + | ||
| 361 | +ge::graphStatus BSATiling::ParseSeqlensInBNSD(gert::TilingContext *bsaContext) | ||
| 362 | +{ | ||
| 363 | + const auto *actualSeqLengths = bsaContext->GetOptionalInputTensor(ACTUAL_SEQ_LENGTHS_INDEX); | ||
| 364 | + const auto *actualSeqLengthsKv = bsaContext->GetOptionalInputTensor(ACTUAL_SEQ_LENGTHS_KV_INDEX); | ||
| 365 | + if (actualSeqLengths != nullptr && actualSeqLengthsKv != nullptr) { | ||
| 366 | + uint32_t batchQS = static_cast<uint32_t>(actualSeqLengths->GetShapeSize()); | ||
| 367 | + uint32_t batchKvS = static_cast<uint32_t>(actualSeqLengthsKv->GetShapeSize()); | ||
| 368 | + if (batch_ != batchKvS || batch_ != batchQS) { | ||
| 369 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 370 | + "ActualSeqLengths & actualSeqLengthsKv must have consistent batch size with each other and context," | ||
| 371 | + "but got batch in actualSeqLengths: %u, batch in actualSeqLengthsKv: %u, " | ||
| 372 | + "batch in context(from query dim0): %u", | ||
| 373 | + batchQS, batchKvS, batch_); | ||
| 374 | + return ge::GRAPH_FAILED; | ||
| 375 | + } | ||
| 376 | + qSeqLenList_ = actualSeqLengths->GetData<int64_t>(); | ||
| 377 | + kvSeqLenList_ = actualSeqLengthsKv->GetData<int64_t>(); | ||
| 378 | + useUniformQSeqlen_ = false; | ||
| 379 | + useUniformKvSeqlen_ = false; | ||
| 380 | + } else if (actualSeqLengths == nullptr && actualSeqLengthsKv == nullptr) { | ||
| 381 | + useUniformQSeqlen_ = true; | ||
| 382 | + useUniformKvSeqlen_ = true; | ||
| 383 | + } else { | ||
| 384 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 385 | + "ActualSeqLengths & actualSeqLengthsKv must be either both provided, or neither provided."); | ||
| 386 | + return ge::GRAPH_FAILED; | ||
| 387 | + } | ||
| 388 | + return ge::GRAPH_SUCCESS; | ||
| 389 | +} | ||
| 390 | + | ||
| 391 | +ge::graphStatus BSATiling::ParseSeqlens(gert::TilingContext *bsaContext) | ||
| 392 | +{ | ||
| 393 | + ge::graphStatus ret = ge::GRAPH_SUCCESS; | ||
| 394 | + if (qInputLayout_ == RFAQInputLayout::TND_Q) { | ||
| 395 | + ret = ParseSeqlensInTND(bsaContext); | ||
| 396 | + } else if (qInputLayout_ == RFAQInputLayout::BNSD_Q) { | ||
| 397 | + ret = ParseSeqlensInBNSD(bsaContext); | ||
| 398 | + } | ||
| 399 | + return ret; | ||
| 400 | +} | ||
| 401 | + | ||
| 402 | +ge::graphStatus BSATiling::CheckSparsePattern(gert::TilingContext *bsaContext, const int64_t defaultShape) | ||
| 403 | +{ | ||
| 404 | + const auto *blockSparseMaskDesc = bsaContext->GetInputDesc(BLOCK_SPARSE_MASK_INDEX); | ||
| 405 | + const auto *blockSparseMaskShape = bsaContext->GetInputShape(BLOCK_SPARSE_MASK_INDEX); | ||
| 406 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, blockSparseMaskDesc); | ||
| 407 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, blockSparseMaskShape); | ||
| 408 | + auto sparsePatternDtype = blockSparseMaskDesc->GetDataType(); | ||
| 409 | + if (sparsePatternDtype == ge::DT_INT8 || sparsePatternDtype == ge::DT_BOOL ) { | ||
| 410 | + sparsePatternMode_ = SPARSE_PATTERN_MODE_MASK; | ||
| 411 | + } else if (sparsePatternDtype == ge::DT_INT32) { | ||
| 412 | + sparsePatternMode_ = SPARSE_PATTERN_MODE_TABLE; | ||
| 413 | + } else { | ||
| 414 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 415 | + "BlockSparseMask only supports int8 mask or int32 sparse table, but got dtype %d.", | ||
| 416 | + static_cast<int32_t>(sparsePatternDtype)); | ||
| 417 | + return ge::GRAPH_FAILED; | ||
| 418 | + } | ||
| 419 | + if (blockShapeX_ <= 0 || blockShapeY_ <= 0) { | ||
| 420 | + OP_LOGE(bsaContext->GetNodeName(), "BlockShape elems must be greater than 0, " | ||
| 421 | + "but got elem0: %ld, elem1: %ld.", blockShapeX_, blockShapeY_); | ||
| 422 | + return ge::GRAPH_FAILED; | ||
| 423 | + } | ||
| 424 | + // temporary regulation of blockShapeY | ||
| 425 | + if (blockShapeY_ % defaultShape != 0) { | ||
| 426 | + OP_LOGE(bsaContext->GetNodeName(), "BlockShape elem1 must be a multiple of 128 so far, " | ||
| 427 | + "but got elem1: %ld.", blockShapeY_); | ||
| 428 | + return ge::GRAPH_FAILED; | ||
| 429 | + } | ||
| 430 | + if (blockSparseMaskShape->GetStorageShape().GetDimNum() != 4) { | ||
| 431 | + printf("Current DimNum%d\n",blockSparseMaskShape->GetStorageShape().GetDimNum()); | ||
| 432 | + //OP_LOGE(bsaContext->GetNodeName(), "BlockSparseMask must have 4 dims."); | ||
| 433 | + //return ge::GRAPH_FAILED; | ||
| 434 | + } | ||
| 435 | + uint32_t bsmBatch = blockSparseMaskShape->GetStorageShape().GetDim(0); // batch_size | ||
| 436 | + uint32_t bsmNumHead = blockSparseMaskShape->GetStorageShape().GetDim(1); // num_heads | ||
| 437 | + if (bsmBatch != batch_) { | ||
| 438 | + OP_LOGE(bsaContext->GetNodeName(), "BlockSparseMask must have consistent batch with context," | ||
| 439 | + "but got BlockSparseMask batch(dim0): %u, context batch: %u.", bsmBatch, batch_); | ||
| 440 | + return ge::GRAPH_FAILED; | ||
| 441 | + } | ||
| 442 | + if (bsmNumHead != numHeads_) { | ||
| 443 | + OP_LOGE(bsaContext->GetNodeName(), "BlockSparseMask must have consistent numHeads with context," | ||
| 444 | + "but got BlockSparseMask numHeads(dim1): %u, context numHeads: %u.", bsmNumHead, numHeads_); | ||
| 445 | + return ge::GRAPH_FAILED; | ||
| 446 | + } | ||
| 447 | + return ge::GRAPH_SUCCESS; | ||
| 448 | +} | ||
| 449 | + | ||
| 450 | +ge::graphStatus BSATiling::ParseSparsePattern(gert::TilingContext *bsaContext) | ||
| 451 | +{ | ||
| 452 | + constexpr int64_t DEFAULT_BLOCK_SHAPE = 128; | ||
| 453 | + blockShapeX_ = DEFAULT_BLOCK_SHAPE; | ||
| 454 | + blockShapeY_ = DEFAULT_BLOCK_SHAPE; | ||
| 455 | + const auto *blockSparseMaskTensor = bsaContext->GetOptionalInputTensor(BLOCK_SPARSE_MASK_INDEX); | ||
| 456 | + const auto *blockShapeTensor = bsaContext->GetOptionalInputTensor(BLOCK_SHAPE_INDEX); | ||
| 457 | + | ||
| 458 | + if (blockSparseMaskTensor == nullptr) { | ||
| 459 | + OP_LOGE(bsaContext->GetNodeName(), "BlockSparseMask should be provided so far."); | ||
| 460 | + return ge::GRAPH_FAILED; | ||
| 461 | + } | ||
| 462 | + if (blockShapeTensor != nullptr) { | ||
| 463 | + uint32_t blockShapeElemNum = static_cast<uint32_t>(blockShapeTensor->GetShapeSize()); | ||
| 464 | + if (blockShapeElemNum != 2) { | ||
| 465 | + OP_LOGE(bsaContext->GetNodeName(), "BlockShape elem num must be 2."); | ||
| 466 | + return ge::GRAPH_FAILED; | ||
| 467 | + } | ||
| 468 | + blockShapeList = blockShapeTensor->GetData<int64_t>(); | ||
| 469 | + if (blockShapeList != nullptr) { | ||
| 470 | + blockShapeX_ = blockShapeList[0]; | ||
| 471 | + blockShapeY_ = blockShapeList[1]; | ||
| 472 | + } | ||
| 473 | + } | ||
| 474 | + if (CheckSparsePattern(bsaContext, DEFAULT_BLOCK_SHAPE) != ge::GRAPH_SUCCESS) { | ||
| 475 | + return ge::GRAPH_FAILED; | ||
| 476 | + } | ||
| 477 | + return ge::GRAPH_SUCCESS; | ||
| 478 | +} | ||
| 479 | + | ||
| 480 | +ge::graphStatus BSATiling::ParseAttenMask(gert::TilingContext *bsaContext) | ||
| 481 | +{ | ||
| 482 | + const auto *attenMaskTensor = bsaContext->GetOptionalInputTensor(ATTEN_MASK_INDEX); | ||
| 483 | + if (attenMaskTensor != nullptr) { | ||
| 484 | + OP_LOGE(bsaContext->GetNodeName(), "AttenMask is NOT YET supported."); | ||
| 485 | + return ge::GRAPH_FAILED; | ||
| 486 | + } | ||
| 487 | + return ge::GRAPH_SUCCESS; | ||
| 488 | +} | ||
| 489 | + | ||
| 490 | +ge::graphStatus BSATiling::ParseBlockTable(gert::TilingContext *bsaContext) | ||
| 491 | +{ | ||
| 492 | + const auto *blockTableTensor = bsaContext->GetOptionalInputTensor(BLOCK_TABLE_INDEX); | ||
| 493 | + if (blockTableTensor != nullptr) { | ||
| 494 | + OP_LOGE(bsaContext->GetNodeName(), | ||
| 495 | + "Paged cache is NOT YET supported, therefore blockTable should be nullptr."); | ||
| 496 | + return ge::GRAPH_FAILED; | ||
| 497 | + } | ||
| 498 | + return ge::GRAPH_SUCCESS; | ||
| 499 | +} | ||
| 500 | + | ||
| 501 | +ge::graphStatus BSATiling::ParseOptionalTensors(gert::TilingContext *bsaContext) | ||
| 502 | +{ | ||
| 503 | + if (ParseSeqlens(bsaContext) != ge::GRAPH_SUCCESS || | ||
| 504 | + ParseSparsePattern(bsaContext) != ge::GRAPH_SUCCESS || | ||
| 505 | + ParseAttenMask(bsaContext) != ge::GRAPH_SUCCESS || | ||
| 506 | + ParseBlockTable(bsaContext) != ge::GRAPH_SUCCESS) { | ||
| 507 | + return ge::GRAPH_FAILED; | ||
| 508 | + } | ||
| 509 | + return ge::GRAPH_SUCCESS; | ||
| 510 | +} | ||
| 511 | + | ||
| 512 | +ge::graphStatus BSATiling::ParseAttrs(gert::TilingContext *bsaContext) | ||
| 513 | +{ | ||
| 514 | + auto attrs = bsaContext->GetAttrs(); | ||
| 515 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, attrs); | ||
| 516 | + if (attrs->GetAttrPointer<uint32_t>(NUM_KEY_VALUE_HEADS_INDEX) == nullptr) { | ||
| 517 | + OP_LOGE(bsaContext->GetNodeName(), "numKeyValueHeads is null"); | ||
| 518 | + return ge::GRAPH_FAILED; | ||
| 519 | + } | ||
| 520 | + kvHeads_ = *attrs->GetAttrPointer<uint32_t>(NUM_KEY_VALUE_HEADS_INDEX); | ||
| 521 | + | ||
| 522 | + if (attrs->GetAttrPointer<float>(SCALE_VALUE_INDEX) == nullptr) { | ||
| 523 | + scaleValue_ = 1.0f / std::sqrt(static_cast<float>(embeddingSize_)); | ||
| 524 | + } else { | ||
| 525 | + scaleValue_ = *attrs->GetAttrPointer<float>(SCALE_VALUE_INDEX); | ||
| 526 | + } | ||
| 527 | + | ||
| 528 | + if (attrs->GetAttrPointer<uint32_t>(MASK_TYPE_INDEX) != nullptr) { | ||
| 529 | + maskType_ = *attrs->GetAttrPointer<uint32_t>(MASK_TYPE_INDEX); | ||
| 530 | + } | ||
| 531 | + | ||
| 532 | + // 获取innerPrecise参数 | ||
| 533 | + if (attrs->GetAttrPointer<uint32_t>(INNER_PRECISE_INDEX) != nullptr) { | ||
| 534 | + innerPrecise_ = *attrs->GetAttrPointer<uint32_t>(INNER_PRECISE_INDEX); | ||
| 535 | + } | ||
| 536 | + if (socVer_ == SOC_VER_950_CODE) { | ||
| 537 | + if (innerPrecise_ != BsaInnerCalcPrec::LOW_HIGH_MIXED) { | ||
| 538 | + OP_LOGE(bsaContext->GetNodeName(), "On chip 950, only innerPrec = 4 is supported, " | ||
| 539 | + "but got %u.", innerPrecise_); | ||
| 540 | + return ge::GRAPH_FAILED; | ||
| 541 | + } | ||
| 542 | + } else { | ||
| 543 | + auto qInputDesc = bsaContext->GetInputDesc(QUERY_INDEX); | ||
| 544 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, qInputDesc); | ||
| 545 | + auto dtypeQ = qInputDesc->GetDataType(); | ||
| 546 | + if (innerPrecise_ != BsaInnerCalcPrec::ALL_HIGH && innerPrecise_ != BsaInnerCalcPrec::ALL_LOW) { | ||
| 547 | + OP_LOGE(bsaContext->GetNodeName(), "On chip 910 & 910_93, only innerPrec = 0 or 1 is supported, " | ||
| 548 | + "but got %u.", innerPrecise_); | ||
| 549 | + return ge::GRAPH_FAILED; | ||
| 550 | + } else if (innerPrecise_ == BsaInnerCalcPrec::ALL_LOW && dtypeQ == ge::DT_BF16) { | ||
| 551 | + OP_LOGE(bsaContext->GetNodeName(), "On chip 910 & 910_93, when query dtype is bfloat16, " | ||
| 552 | + "only innerPrec = 0 is supported, but got %u.", innerPrecise_); | ||
| 553 | + return ge::GRAPH_FAILED; | ||
| 554 | + } | ||
| 555 | + } | ||
| 556 | + // reserved yet non-configurable attrs | ||
| 557 | + int64_t blockSize = *attrs->GetAttrPointer<int64_t>(BLOCK_SIZE_INDEX); | ||
| 558 | + if (blockSize != 0) { | ||
| 559 | + OP_LOGE(bsaContext->GetNodeName(), "Since paged cache is not yet supported, " | ||
| 560 | + "blocksize must be 0, but got %ld.", blockSize); | ||
| 561 | + return ge::GRAPH_FAILED; | ||
| 562 | + } | ||
| 563 | + int64_t preTokens = *attrs->GetAttrPointer<int64_t>(PRE_TOKENS_INDEX); | ||
| 564 | + int64_t nextTokens = *attrs->GetAttrPointer<int64_t>(NEXT_TOKENS_INDEX); | ||
| 565 | + if (preTokens != INF_WINDOW_SIZE_PRE_NEXT || nextTokens != INF_WINDOW_SIZE_PRE_NEXT) { | ||
| 566 | + OP_LOGE(bsaContext->GetNodeName(), "Since windowed atten mask is not yet supported, " | ||
| 567 | + "preTokens & nextTokens must be 2147483647, but got %ld, %ld.", preTokens, nextTokens); | ||
| 568 | + return ge::GRAPH_FAILED; | ||
| 569 | + } | ||
| 570 | + auto softmaxLsePtr = attrs->GetAttrPointer<int64_t>(SOFTMAX_LSE_FLAG_INDEX); | ||
| 571 | + if (softmaxLsePtr == nullptr) { | ||
| 572 | + OP_LOGE(bsaContext->GetNodeName(), "Attr softmaxLseFlag is nullptr."); | ||
| 573 | + return ge::GRAPH_FAILED; | ||
| 574 | + } else if (*softmaxLsePtr == LSE_OUT) { | ||
| 575 | + if (socVer_ == SOC_VER_950_CODE) { | ||
| 576 | + OP_LOGE(bsaContext->GetNodeName(), "Attr softmaxLseFlag must be 0 on chip 950."); | ||
| 577 | + return ge::GRAPH_FAILED; | ||
| 578 | + } | ||
| 579 | + softmaxLseFlag_ = true; | ||
| 580 | + } else if (*softmaxLsePtr == LSE_NO_OUT) { | ||
| 581 | + softmaxLseFlag_ = false; | ||
| 582 | + } else { | ||
| 583 | + OP_LOGE(bsaContext->GetNodeName(), "Attr softmaxLseFlag must be 0 or 1, but got: %ld.", *softmaxLsePtr); | ||
| 584 | + return ge::GRAPH_FAILED; | ||
| 585 | + } | ||
| 586 | + | ||
| 587 | + return ge::GRAPH_SUCCESS; | ||
| 588 | +} | ||
| 589 | + | ||
| 590 | +void BSATiling::CalculateBatchTaskSplit(int64_t qSeqlen, uint32_t groupSize, | ||
| 591 | + uint32_t &curTaskNum, uint32_t &curQBlockNum) | ||
| 592 | +{ | ||
| 593 | + uint32_t curQBlockTile = GetQNBlockTile(); | ||
| 594 | + uint32_t qNBlockNumPerGroup = CeilDiv(groupSize, curQBlockTile); | ||
| 595 | + uint32_t curQNBlockNum = qNBlockNumPerGroup * kvHeads_; | ||
| 596 | + curTaskNum = GetQBlocks(qSeqlen, blockShapeX_) * curQNBlockNum; | ||
| 597 | + curQBlockNum = CeilDiv(qSeqlen, blockShapeX_) * numHeads_; | ||
| 598 | +} | ||
| 599 | + | ||
| 600 | +uint32_t BSATiling::GetCurQSTileNum950(int64_t curQSeqlen) | ||
| 601 | +{ | ||
| 602 | + uint32_t fullXBlockNum = curQSeqlen / blockShapeX_; | ||
| 603 | + uint32_t tailXBlockSize = curQSeqlen % blockShapeX_; | ||
| 604 | + uint32_t qSTileNumPerFullXBlock = (blockShapeX_ + qBaseTile_ - 1) / qBaseTile_; | ||
| 605 | + uint32_t qSTileNumTailXBlock = (tailXBlockSize + qBaseTile_ - 1) / qBaseTile_; | ||
| 606 | + uint32_t curQSTileNum = qSTileNumPerFullXBlock * fullXBlockNum + qSTileNumTailXBlock; | ||
| 607 | + return curQSTileNum; | ||
| 608 | +} | ||
| 609 | + | ||
| 610 | +void BSATiling::CalcBaseTileTilingParams950() | ||
| 611 | +{ | ||
| 612 | + qBaseTile_ = (blockShapeX_ > TILE_SIZE_128) ? TILE_SIZE_128 : blockShapeX_; | ||
| 613 | + if (innerPrecise_ == BsaInnerCalcPrec::LOW_HIGH_MIXED && embeddingSize_ <= D_SIZE_128) { | ||
| 614 | + kvBaseTile_ = TILE_SIZE_512; | ||
| 615 | + } else { | ||
| 616 | + kvBaseTile_ = TILE_SIZE_128; | ||
| 617 | + } | ||
| 618 | +} | ||
| 619 | + | ||
| 620 | +void BSATiling::CalcSplitCoreTilingParams950() | ||
| 621 | +{ | ||
| 622 | + CalcBaseTileTilingParams950(); | ||
| 623 | + for (uint32_t bIdx = 0; bIdx < batch_; bIdx++) { | ||
| 624 | + int64_t curQSeqlen = useUniformQSeqlen_ ? maxQSeqlen_ : qSeqLenList_[bIdx]; | ||
| 625 | + int64_t curKvSeqlen = useUniformKvSeqlen_ ? maxKvSeqlen_ : kvSeqLenList_[bIdx]; | ||
| 626 | + uint32_t curQSTileNum = GetCurQSTileNum950(curQSeqlen); | ||
| 627 | + uint32_t curBatchTaskNum = curQSTileNum * numHeads_; | ||
| 628 | + totalTaskNum_ += curBatchTaskNum; | ||
| 629 | + if (bIdx == 0) { | ||
| 630 | + firstBatchTaskNum_ = curBatchTaskNum; | ||
| 631 | + } | ||
| 632 | + maxQSeqlen_ = (curQSeqlen > maxQSeqlen_) ? curQSeqlen : maxQSeqlen_; | ||
| 633 | + maxKvSeqlen_ = (curKvSeqlen > maxKvSeqlen_) ? curKvSeqlen : maxKvSeqlen_; | ||
| 634 | + } | ||
| 635 | + blockDim_ = aicNum_; | ||
| 636 | + // mask2idx split core | ||
| 637 | + xBlockNumAligned_ = (maxQSeqlen_ + blockShapeX_ - 1) / blockShapeX_; | ||
| 638 | + yBlockNumAligned_ = (maxKvSeqlen_ + blockShapeY_ - 1) / blockShapeY_; | ||
| 639 | + uint32_t totalRowNumBlockMask = batch_ * numHeads_ * xBlockNumAligned_; | ||
| 640 | + avgRowPerSubCore_ = (totalRowNumBlockMask + aivNum_ - 1) / aivNum_; | ||
| 641 | + preActiveSubCoreNum_ = (totalRowNumBlockMask + avgRowPerSubCore_ - 1) / avgRowPerSubCore_; | ||
| 642 | +} | ||
| 643 | + | ||
| 644 | +ge::graphStatus BSATiling::CalculateTaskSplit(gert::TilingContext *bsaContext) | ||
| 645 | +{ | ||
| 646 | + // 计算总的Q块数量和最大KV块数量 | ||
| 647 | + totalQBlocks_ = 0; | ||
| 648 | + | ||
| 649 | + if (kvHeads_ == 0) { | ||
| 650 | + OP_LOGE(bsaContext->GetNodeName(), "kvHeads_ is 0, cannot calculate groupSize"); | ||
| 651 | + return ge::GRAPH_FAILED; | ||
| 652 | + } | ||
| 653 | + if (batch_ == 0) { | ||
| 654 | + OP_LOGE(bsaContext->GetNodeName(), "batch_ is 0 in CalculateTaskSplit"); | ||
| 655 | + return ge::GRAPH_FAILED; | ||
| 656 | + } | ||
| 657 | + | ||
| 658 | + // 根据useUniformQSeqlen_标志位决定分核时使用actualSeqLengths数组还是maxQSeqlen_ | ||
| 659 | + uint32_t groupSize = numHeads_ / kvHeads_; | ||
| 660 | + | ||
| 661 | + // 遍历每个batch进行分核计算 | ||
| 662 | + for (auto i = 0; i < batch_; i++) { | ||
| 663 | + // 根据useUniformQSeqlen_标志位决定使用actualSeqLengths数组还是maxQSeqlen_ | ||
| 664 | + int64_t qSeqlen; | ||
| 665 | + if (useUniformQSeqlen_) { | ||
| 666 | + // BNSD格式下actualSeqLengths为nullptr,使用maxQSeqlen_作为统一的qseqlen值 | ||
| 667 | + qSeqlen = static_cast<int64_t>(maxQSeqlen_); | ||
| 668 | + } else { | ||
| 669 | + // 使用actualSeqLengths数组(TND格式或BNSD格式但提供了actualSeqLengths) | ||
| 670 | + if (qSeqLenList_ == nullptr) { | ||
| 671 | + OP_LOGE(bsaContext->GetNodeName(), "qSeqLenList_ is nullptr, cannot calculate task split"); | ||
| 672 | + return ge::GRAPH_FAILED; | ||
| 673 | + } | ||
| 674 | + qSeqlen = qSeqLenList_[i]; | ||
| 675 | + } | ||
| 676 | + | ||
| 677 | + uint32_t curTaskNum = 0; | ||
| 678 | + uint32_t curQBlockNum = 0; | ||
| 679 | + CalculateBatchTaskSplit(qSeqlen, groupSize, curTaskNum, curQBlockNum); | ||
| 680 | + | ||
| 681 | + if (i == 0) { | ||
| 682 | + firstBatchTaskNum_ = curTaskNum; | ||
| 683 | + firstQBlockNum_ = curQBlockNum; | ||
| 684 | + } | ||
| 685 | + totalTaskNum_ += curTaskNum; | ||
| 686 | + totalQBlocks_ += curQBlockNum; | ||
| 687 | + } | ||
| 688 | + blockDim_ = std::min(aicNum_, totalTaskNum_); | ||
| 689 | + return ge::GRAPH_SUCCESS; | ||
| 690 | +} | ||
| 691 | + | ||
| 692 | +void BSATiling::CalcWorkspaceTilingParams950(gert::TilingContext *bsaContext) | ||
| 693 | +{ | ||
| 694 | + selectIdxSize_ = (sparsePatternMode_ == SPARSE_PATTERN_MODE_TABLE) ? | ||
| 695 | + 0 : batch_ * numHeads_ * xBlockNumAligned_ * yBlockNumAligned_ * sizeof(int32_t); | ||
| 696 | + selectNumIdxSize_ = batch_ * numHeads_ * xBlockNumAligned_ * sizeof(int32_t); | ||
| 697 | + workSpaceSize_ = libapiSize_ + selectIdxSize_ + selectNumIdxSize_; | ||
| 698 | + bsaContext->GetWorkspaceSizes(1)[0] = workSpaceSize_; | ||
| 699 | +} | ||
| 700 | + | ||
| 701 | +ge::graphStatus BSATiling::CalculateWorkSpace(gert::TilingContext *bsaContext) | ||
| 702 | +{ | ||
| 703 | + if (blockDim_ == 0) { | ||
| 704 | + OP_LOGE(bsaContext->GetNodeName(), "blockDim is 0"); | ||
| 705 | + return ge::GRAPH_FAILED; | ||
| 706 | + } | ||
| 707 | + | ||
| 708 | + const auto *blockSparseMaskShape = bsaContext->GetInputShape(BLOCK_SPARSE_MASK_INDEX); | ||
| 709 | + maxKvBlockNum_ = blockSparseMaskShape->GetStorageShape().GetDim(3); | ||
| 710 | + maxQBlockNum_ = blockSparseMaskShape->GetStorageShape().GetDim(2); | ||
| 711 | + selectIdxSize_ = (sparsePatternMode_ == SPARSE_PATTERN_MODE_TABLE) ? | ||
| 712 | + 0 : CeilDiv(blockShapeX_, 128) * CeilDiv(maxKvBlockNum_, 32) * 32 * sizeof(uint32_t) * batch_ * numHeads_ * maxQBlockNum_; | ||
| 713 | + selectNumIdxSize_ = CeilDiv(blockShapeX_, 128) * sizeof(uint32_t) * 32 * batch_ * numHeads_ * maxQBlockNum_; | ||
| 714 | + int32_t syncSize_ = sizeof(uint32_t) * 256; | ||
| 715 | + | ||
| 716 | + mm1OutSize_ = blockDim_ * WORKSPACE_BLOCK_SIZE_DB * sizeof(float) * NUM3; | ||
| 717 | + smOnlineOutSize_ = blockDim_ * WORKSPACE_BLOCK_SIZE_DB * sizeof(uint16_t) * NUM3; | ||
| 718 | + mm2OutSize_ = blockDim_ * WORKSPACE_BLOCK_SIZE_DB * sizeof(float) * NUM3; | ||
| 719 | + updateSize_ = blockDim_ * WORKSPACE_BLOCK_SIZE_DB * sizeof(float) * NUM3; | ||
| 720 | + | ||
| 721 | + workSpaceSize_ = libapiSize_ + mm1OutSize_ + smOnlineOutSize_ + mm2OutSize_ + updateSize_ + selectNumIdxSize_ + selectIdxSize_ + syncSize_; | ||
| 722 | + bsaContext->GetWorkspaceSizes(1)[0] = workSpaceSize_; | ||
| 723 | + uint32_t totalTaskNumMask = batch_ * numHeads_ * maxQBlockNum_; | ||
| 724 | + avgRowNumPerSubCore_ = CeilDiv(totalTaskNumMask, blockDim_ * 2); | ||
| 725 | + preActivateSubCoreNum_ = CeilDiv(totalTaskNumMask, avgRowNumPerSubCore_); | ||
| 726 | + | ||
| 727 | + return ge::GRAPH_SUCCESS; | ||
| 728 | +} | ||
| 729 | + | ||
| 730 | +void BSATiling::CalcMatmulPhaseL1TileInfo950() | ||
| 731 | +{ | ||
| 732 | + uint32_t qBaseTileAligned128 = (qBaseTile_ + TILE_SIZE_128 - 1) / TILE_SIZE_128 * TILE_SIZE_128; | ||
| 733 | + uint32_t embeddingSizeAligned128 = (embeddingSize_ + TILE_SIZE_128 - 1) / TILE_SIZE_128 * TILE_SIZE_128; | ||
| 734 | + uint32_t kvBaseTileAligned128 = (kvBaseTile_ + TILE_SIZE_128 - 1) / TILE_SIZE_128 * TILE_SIZE_128; | ||
| 735 | + | ||
| 736 | + // 基本原则,Q的基块常驻在L1 | ||
| 737 | + mm1L1TileM_ = qBaseTileAligned128; | ||
| 738 | + mm1L1TileKLeft_ = embeddingSizeAligned128; | ||
| 739 | + qL1BufNum_ = SOLO_BUF; | ||
| 740 | + if (embeddingSizeAligned128 == D_SIZE_256) { | ||
| 741 | + // K矩阵开启2buf,D按256分割,S2按128分割 | ||
| 742 | + // 可以证明,当Q常驻在L1时,无论D和kvBaseTile_为多少,均不会有QK的MTE2重复搬运 | ||
| 743 | + mm1L1TileN_ = TILE_SIZE_128; | ||
| 744 | + mm1L1TileKRight_ = TILE_SIZE_256; | ||
| 745 | + kL1BufNum_ = DUO_BUF; | ||
| 746 | + // V矩阵D按256分割,kvBaseTile_不分割,指令提前于核间同步下发,是否开启db取决于kvBaseTile_的大小 | ||
| 747 | + mm2L1TileN_ = TILE_SIZE_256; | ||
| 748 | + mm2L1TileKLeft_ = kvBaseTileAligned128; | ||
| 749 | + vL1BufNum_ = TILE_SIZE_256 / kvBaseTileAligned128; | ||
| 750 | + // P矩阵在950上会常驻L1,由于基块的prelaunch为2,因此最好有3 buf,以免基块间流水阻塞 | ||
| 751 | + mm2L1TileM_ = qBaseTileAligned128; | ||
| 752 | + mm2L1TileKRight_ = kvBaseTileAligned128; | ||
| 753 | + pL1BufNum_ = TRIO_BUF; | ||
| 754 | + } else if (embeddingSizeAligned128 == D_SIZE_128) { | ||
| 755 | + // K矩阵开启2buf,D按128分割,S2按512分割 | ||
| 756 | + mm1L1TileN_ = TILE_SIZE_512; | ||
| 757 | + mm1L1TileKRight_ = TILE_SIZE_128; | ||
| 758 | + kL1BufNum_ = DUO_BUF; | ||
| 759 | + // V矩阵开启db,D按128分割,kvBaseTile_不分割,指令同样提前于核间同步下发 | ||
| 760 | + // 如果kvBaseTile_进一步增大,考虑关闭db,使得kvBaseTile_不分割 | ||
| 761 | + mm2L1TileN_ = TILE_SIZE_128; | ||
| 762 | + mm2L1TileKLeft_ = kvBaseTileAligned128; | ||
| 763 | + vL1BufNum_ = DUO_BUF; | ||
| 764 | + // P矩阵在950上会常驻L1,由于基块的prelaunch为2,因此最好有3 buf,以免基块间流水阻塞 | ||
| 765 | + mm2L1TileM_ = qBaseTileAligned128; | ||
| 766 | + mm2L1TileKRight_ = kvBaseTileAligned128; | ||
| 767 | + pL1BufNum_ = TRIO_BUF; | ||
| 768 | + } | ||
| 769 | +} | ||
| 770 | + | ||
| 771 | +ge::graphStatus BSATiling::FillTilingData(gert::TilingContext *bsaContext) | ||
| 772 | +{ | ||
| 773 | + if (tilingData_ == nullptr) { | ||
| 774 | + return ge::GRAPH_FAILED; | ||
| 775 | + } | ||
| 776 | + tilingData_->set_numHeads(numHeads_); | ||
| 777 | + tilingData_->set_embeddingSize(embeddingSize_); | ||
| 778 | + tilingData_->set_blockSize(blockSize_); | ||
| 779 | + tilingData_->set_kvHeads(kvHeads_); | ||
| 780 | + tilingData_->set_batch(batch_); | ||
| 781 | + tilingData_->set_maxNumBlocksPerBatch(maxNumBlocksPerBatch_); | ||
| 782 | + tilingData_->set_firstBatchTaskNum(firstBatchTaskNum_); | ||
| 783 | + tilingData_->set_totalTaskNum(totalTaskNum_); | ||
| 784 | + tilingData_->set_maskType(maskType_); | ||
| 785 | + | ||
| 786 | + tilingData_->set_blockShapeX(blockShapeX_); | ||
| 787 | + tilingData_->set_blockShapeY(blockShapeY_); | ||
| 788 | + | ||
| 789 | + tilingData_->set_firstQBlockNum(firstQBlockNum_); | ||
| 790 | + tilingData_->set_totalQBlocks(totalQBlocks_); | ||
| 791 | + tilingData_->set_maxKvBlockNum(maxKvBlockNum_); | ||
| 792 | + tilingData_->set_maxQBlockNum(maxQBlockNum_); | ||
| 793 | + tilingData_->set_avgRowNumPerSubCore(avgRowNumPerSubCore_); | ||
| 794 | + tilingData_->set_preActivateSubCoreNum(preActivateSubCoreNum_); | ||
| 795 | + | ||
| 796 | + tilingData_->set_kvCacheLayout(static_cast<uint32_t>(kvCacheLayout_)); | ||
| 797 | + tilingData_->set_queryLayout(static_cast<uint32_t>(qInputLayout_)); | ||
| 798 | + tilingData_->set_maxQSeqlen(maxQSeqlen_); | ||
| 799 | + tilingData_->set_maxKvSeqlen(maxKvSeqlen_); | ||
| 800 | + tilingData_->set_sparsePatternMode(sparsePatternMode_); | ||
| 801 | + // BNSD格式下当actualSeqLengths为nullptr时,使用maxQSeqlen和maxKvSeqlen作为统一值 | ||
| 802 | + tilingData_->set_useUniformQSeqlen(useUniformQSeqlen_ ? 1 : 0); | ||
| 803 | + tilingData_->set_useUniformKvSeqlen(useUniformKvSeqlen_ ? 1 : 0); | ||
| 804 | + | ||
| 805 | + // 生成tilingKey(按照开发规范:在tiling层生成) | ||
| 806 | + uint64_t tilingKey = GenerateTilingKey(bsaContext); | ||
| 807 | + tilingData_->set_tilingKey(tilingKey); | ||
| 808 | + bsaContext->SetTilingKey(tilingKey); | ||
| 809 | + bsaContext->SetBlockDim(blockDim_); | ||
| 810 | + | ||
| 811 | + tilingData_->set_mm1OutSize(mm1OutSize_); | ||
| 812 | + tilingData_->set_smOnlineOutSize(smOnlineOutSize_); | ||
| 813 | + tilingData_->set_mm2OutSize(mm2OutSize_); | ||
| 814 | + tilingData_->set_updateSize(updateSize_); | ||
| 815 | + tilingData_->set_workSpaceSize(workSpaceSize_); | ||
| 816 | + tilingData_->set_scaleValue(scaleValue_); | ||
| 817 | + tilingData_->set_selectNumIdxSize(selectNumIdxSize_); | ||
| 818 | + tilingData_->set_selectIdxSize(selectIdxSize_); | ||
| 819 | + // fill 950 mask2idx tile info | ||
| 820 | + tilingData_->BsaMask2IdxTileInfo.set_xBlockNumAligned(xBlockNumAligned_); | ||
| 821 | + tilingData_->BsaMask2IdxTileInfo.set_yBlockNumAligned(yBlockNumAligned_); | ||
| 822 | + tilingData_->BsaMask2IdxTileInfo.set_avgRowPerSubCore(avgRowPerSubCore_); | ||
| 823 | + tilingData_->BsaMask2IdxTileInfo.set_preActiveSubCoreNum(preActiveSubCoreNum_); | ||
| 824 | + // fill 950 base tile info | ||
| 825 | + tilingData_->BsaBaseTileInfo.set_qBaseTile(qBaseTile_); | ||
| 826 | + tilingData_->BsaBaseTileInfo.set_kvBaseTile(kvBaseTile_); | ||
| 827 | + // fill 950 matmul phase L1 tile info | ||
| 828 | + tilingData_->BsaMmPhaseL1TileInfo.set_mm1L1TileM(mm1L1TileM_); | ||
| 829 | + tilingData_->BsaMmPhaseL1TileInfo.set_mm1L1TileN(mm1L1TileN_); | ||
| 830 | + tilingData_->BsaMmPhaseL1TileInfo.set_mm1L1TileKLeft(mm1L1TileKLeft_); | ||
| 831 | + tilingData_->BsaMmPhaseL1TileInfo.set_mm1L1TileKRight(mm1L1TileKRight_); | ||
| 832 | + tilingData_->BsaMmPhaseL1TileInfo.set_mm2L1TileM(mm2L1TileM_); | ||
| 833 | + tilingData_->BsaMmPhaseL1TileInfo.set_mm2L1TileN(mm2L1TileN_); | ||
| 834 | + tilingData_->BsaMmPhaseL1TileInfo.set_mm2L1TileKLeft(mm2L1TileKLeft_); | ||
| 835 | + tilingData_->BsaMmPhaseL1TileInfo.set_mm2L1TileKRight(mm2L1TileKRight_); | ||
| 836 | + tilingData_->BsaMmPhaseL1TileInfo.set_qL1BufNum(qL1BufNum_); | ||
| 837 | + tilingData_->BsaMmPhaseL1TileInfo.set_kL1BufNum(kL1BufNum_); | ||
| 838 | + tilingData_->BsaMmPhaseL1TileInfo.set_vL1BufNum(vL1BufNum_); | ||
| 839 | + tilingData_->BsaMmPhaseL1TileInfo.set_pL1BufNum(pL1BufNum_); | ||
| 840 | + return ge::GRAPH_SUCCESS; | ||
| 841 | +} | ||
| 842 | + | ||
| 843 | +uint64_t BSATiling::GenerateTilingKey(gert::TilingContext *bsaContext) | ||
| 844 | +{ | ||
| 845 | + /** | ||
| 846 | + * 64位整数,使用十进制位域表示: | ||
| 847 | + * AAAABBBBCCCCDDDDEEEE | ||
| 848 | + * - 位0-1: Q Layout(个位) 2=TND, 3=BNSD | ||
| 849 | + * - 位2-4: Mask Type(千位) 0=NoMask, 3=CausalMask | ||
| 850 | + * - 位5-7: Softmax Precision(十万位) 0=Float, 1=Half | ||
| 851 | + * - 位8-10: PagedCache Flag(千万位) 0=NoCache, 1=WithCache | ||
| 852 | + * - 位11-13: KV Layout(十亿位) 00=TND, 20=BNSD | ||
| 853 | + * - 位14-15: Data Type(百亿位) 00=FP16, 22=BF16 | ||
| 854 | + * - 位16-18: Operator Category(千万亿位) 900=EagleQuantBlockSparseAttention910, 905=EagleQuantBlockSparseAttention950 | ||
| 855 | + * | ||
| 856 | + * 示例: | ||
| 857 | + * - FP16, TND, TND, NoCache, Half, NoMask = 9000000030100002 | ||
| 858 | + * - FP16, TND, TND, NoCache, Float, NoMask = 9000000030000002 | ||
| 859 | + */ | ||
| 860 | + | ||
| 861 | + uint64_t tilingKey = 9000000000000000ULL; // RFA基础值(Operator Category = 900) | ||
| 862 | + if (socVer_ == SOC_VER_950_CODE) { | ||
| 863 | + tilingKey = 9050000000000000ULL; | ||
| 864 | + } | ||
| 865 | + | ||
| 866 | + // [位14-15] Data Type(百亿位) | ||
| 867 | + if (dataType_ == ge::DT_FLOAT16) { | ||
| 868 | + tilingKey += 0; // 00 for FP16 | ||
| 869 | + } else if (dataType_ == ge::DT_BF16) { | ||
| 870 | + tilingKey += 22220ULL; // 22 for BF16 -> 9000000030000002 + 22220 = 9000000030022222 | ||
| 871 | + } else if (dataType_ == ge::DT_INT8) { | ||
| 872 | + auto oOutputDesc = bsaContext->GetOutputDesc(0); | ||
| 873 | + OP_CHECK_NULL_WITH_CONTEXT(bsaContext, oOutputDesc); | ||
| 874 | + auto dtypeO = oOutputDesc->GetDataType(); | ||
| 875 | + if (dtypeO == ge::DT_FLOAT16) { | ||
| 876 | + tilingKey += 44440ULL; // 11 for INT8 output with FP16 | ||
| 877 | + } else if (dtypeO == ge::DT_BF16) { | ||
| 878 | + tilingKey += 55550ULL; // 33 for INT8 output with BF16 | ||
| 879 | + } | ||
| 880 | + } | ||
| 881 | + | ||
| 882 | + // [位11-13] KV Layout(十亿位) | ||
| 883 | + if (kvCacheLayout_ == RFAKvCacheLayout::TND) { | ||
| 884 | + tilingKey += 30000000ULL; // 00 for TND | ||
| 885 | + } else if (kvCacheLayout_ == RFAKvCacheLayout::BNSD) { | ||
| 886 | + tilingKey += 50000000ULL; // 20 for BNSD | ||
| 887 | + } | ||
| 888 | + | ||
| 889 | + // [位8-10] PagedCache Flag(千万位) | ||
| 890 | + bool hasPagedCache = (bsaContext->GetOptionalInputTensor(BLOCK_TABLE_INDEX) != nullptr); | ||
| 891 | + if (hasPagedCache) { | ||
| 892 | + tilingKey += 1000000ULL; // 1 for WithCache | ||
| 893 | + } | ||
| 894 | + | ||
| 895 | + // [位5-7] Softmax Precision(十万位) | ||
| 896 | + if (innerPrecise_ == 1) { | ||
| 897 | + tilingKey += 100000ULL; // 1 for Half (FP16) Softmax | ||
| 898 | + } else if (innerPrecise_ == 4) { | ||
| 899 | + tilingKey += 400000ULL; // 4 for low prec online softmax & high prec rescale O | ||
| 900 | + } | ||
| 901 | + // innerPrecise_ == 0: 0 for Float Softmax(默认值) | ||
| 902 | + | ||
| 903 | + // [位2-4] Mask Type(千位) | ||
| 904 | + if (maskType_ == 3) { // Causal mask | ||
| 905 | + tilingKey += 3000ULL; | ||
| 906 | + } | ||
| 907 | + // maskType_ == 0: 0 for NoMask(默认值) | ||
| 908 | + | ||
| 909 | + // [位0-1] Q Layout(个位) | ||
| 910 | + if (qInputLayout_ == RFAQInputLayout::TND_Q) { | ||
| 911 | + tilingKey += 2; // 2 for TND | ||
| 912 | + } else if (qInputLayout_ == RFAQInputLayout::BNSD_Q) { | ||
| 913 | + tilingKey += 3; // 3 for BNSD | ||
| 914 | + } | ||
| 915 | + | ||
| 916 | + // Softmax LSE(亿位) | ||
| 917 | + if (softmaxLseFlag_) { | ||
| 918 | + tilingKey += 100000000ULL; // 1 for lse out | ||
| 919 | + } | ||
| 920 | + | ||
| 921 | + constexpr uint64_t V_DTYPE_OFFSET = 10000000000ULL; // 10^10 | ||
| 922 | + if (vDataType_ == ge::DT_FLOAT8_E4M3FN || vDataType_ == ge::DT_INT8) { | ||
| 923 | + tilingKey += V_DTYPE_OFFSET * 1ULL; | ||
| 924 | + } else if (vDataType_ == ge::DT_FLOAT8_E5M2) { | ||
| 925 | + tilingKey += V_DTYPE_OFFSET * 2ULL; | ||
| 926 | + } | ||
| 927 | + // vDataType 与 Q/K 相同时,加 0,保持兼容 | ||
| 928 | + | ||
| 929 | + | ||
| 930 | + return tilingKey; | ||
| 931 | +} | ||
| 932 | + | ||
| 933 | +ge::graphStatus BSATiling::GetBsaTiling(gert::TilingContext *bsaContext, | ||
| 934 | + EagleQuantBlockSparseAttentionTilingData &tilingData) | ||
| 935 | +{ | ||
| 936 | + tilingData_ = &tilingData; | ||
| 937 | + ge::graphStatus ret = GetNpuInfo(bsaContext); | ||
| 938 | + if (ret != ge::GRAPH_SUCCESS) { | ||
| 939 | + OP_LOGE(bsaContext->GetNodeName(), "GetNpuInfo failed"); | ||
| 940 | + return ret; | ||
| 941 | + } | ||
| 942 | + if (GetInputLayout(bsaContext) != ge::GRAPH_SUCCESS || | ||
| 943 | + ParseAttrs(bsaContext) != ge::GRAPH_SUCCESS || | ||
| 944 | + ParseRequiredTensors(bsaContext) != ge::GRAPH_SUCCESS || | ||
| 945 | + ParseOptionalTensors(bsaContext) != ge::GRAPH_SUCCESS) { | ||
| 946 | + ret = ge::GRAPH_FAILED; | ||
| 947 | + return ret; | ||
| 948 | + } | ||
| 949 | + // 校验TND格式下qseqlen和kvseqlen之和是否分别等于Q和KV的T | ||
| 950 | + ret = ValidateTNDSeqlenSum(bsaContext); | ||
| 951 | + if (ret != ge::GRAPH_SUCCESS) { | ||
| 952 | + OP_LOGE(bsaContext->GetNodeName(), "ValidateTNDSeqlenSum failed"); | ||
| 953 | + return ret; | ||
| 954 | + } | ||
| 955 | + | ||
| 956 | + if (socVer_ == SOC_VER_950_CODE) { | ||
| 957 | + CalcSplitCoreTilingParams950(); | ||
| 958 | + CalcMatmulPhaseL1TileInfo950(); | ||
| 959 | + CalcWorkspaceTilingParams950(bsaContext); | ||
| 960 | + } else { | ||
| 961 | + ret = CalculateTaskSplit(bsaContext); | ||
| 962 | + if (ret != ge::GRAPH_SUCCESS) { | ||
| 963 | + OP_LOGE(bsaContext->GetNodeName(), "CalculateTaskSplit failed"); | ||
| 964 | + return ret; | ||
| 965 | + } | ||
| 966 | + ret = CalculateWorkSpace(bsaContext); | ||
| 967 | + if (ret != ge::GRAPH_SUCCESS) { | ||
| 968 | + OP_LOGE(bsaContext->GetNodeName(), "CalculateWorkSpace failed"); | ||
| 969 | + return ret; | ||
| 970 | + } | ||
| 971 | + } | ||
| 972 | + | ||
| 973 | + ret = FillTilingData(bsaContext); | ||
| 974 | + if (ret != ge::GRAPH_SUCCESS) { | ||
| 975 | + OP_LOGE(bsaContext->GetNodeName(), "FillTilingData failed"); | ||
| 976 | + return ret; | ||
| 977 | + } | ||
| 978 | + return ge::GRAPH_SUCCESS; | ||
| 979 | +} | ||
| 980 | + | ||
| 981 | +ge::graphStatus BSATiling::BsaSetTilingData(gert::TilingContext *context, | ||
| 982 | + EagleQuantBlockSparseAttentionTilingData &tilingData) | ||
| 983 | +{ | ||
| 984 | + OP_CHECK_IF(context->GetRawTilingData() == nullptr, | ||
| 985 | + OPS_REPORT_VECTOR_INNER_ERR("EagleQuantBlockSparseAttention", | ||
| 986 | + "RawTilingData got from GE context is nullptr."), return ge::GRAPH_FAILED); | ||
| 987 | + tilingData.SaveToBuffer(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity()); | ||
| 988 | + context->GetRawTilingData()->SetDataSize(tilingData.GetDataSize()); | ||
| 989 | + return ge::GRAPH_SUCCESS; | ||
| 990 | +} | ||
| 991 | + | ||
| 992 | +ASCENDC_EXTERN_C ge::graphStatus TilingEagleQuantBlockSparseAttention(gert::TilingContext* context) | ||
| 993 | +{ | ||
| 994 | + OP_CHECK_IF(context == nullptr, OPS_REPORT_VECTOR_INNER_ERR("EagleQuantBlockSparseAttention", | ||
| 995 | + "Context is nullptr."), return ge::GRAPH_FAILED); | ||
| 996 | + EagleQuantBlockSparseAttentionTilingData tilingData; | ||
| 997 | + BSATiling bsaTiling; | ||
| 998 | + if (bsaTiling.GetBsaTiling(context, tilingData) == ge::GRAPH_SUCCESS) { | ||
| 999 | + bsaTiling.BsaSetTilingData(context, tilingData); | ||
| 1000 | + return ge::GRAPH_SUCCESS; | ||
| 1001 | + } else { | ||
| 1002 | + OP_LOGE(context->GetNodeName(), "GetBsaTiling failed"); | ||
| 1003 | + return ge::GRAPH_FAILED; | ||
| 1004 | + } | ||
| 1005 | +} | ||
| 1006 | + | ||
| 1007 | +ASCENDC_EXTERN_C ge::graphStatus TilingPrepareForEagleQuantBlockSparseAttention(gert::TilingParseContext* context) | ||
| 1008 | +{ | ||
| 1009 | + (void) context; | ||
| 1010 | + return ge::GRAPH_SUCCESS; | ||
| 1011 | +} | ||
| 1012 | + | ||
| 1013 | +IMPL_OP_OPTILING(EagleQuantBlockSparseAttention) | ||
| 1014 | + .Tiling(TilingEagleQuantBlockSparseAttention) | ||
| 1015 | + .TilingInputsDataDependency({5, 6, 7}, {gert::TilingPlacement::TILING_ON_HOST, gert::TilingPlacement::TILING_ON_AICPU}) | ||
| 1016 | + .TilingParse<EagleQuantBlockSparseAttentionCompileInfo>(TilingPrepareForEagleQuantBlockSparseAttention); // 向框架注册入口函数; | ||
| 1017 | + | ||
| 1018 | +} // namespace optiling | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_host/eagle_quant_block_sparse_attention_tiling.h+286-0
| @@ -0,0 +1,286 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace optiling { | ||
| 21 | +// mask 2 idx tile info | ||
| 22 | +BEGIN_TILING_DATA_DEF(BsaMask2IdxTiling) | ||
| 23 | +TILING_DATA_FIELD_DEF(uint32_t, xBlockNumAligned); | ||
| 24 | +TILING_DATA_FIELD_DEF(uint32_t, yBlockNumAligned); | ||
| 25 | +TILING_DATA_FIELD_DEF(uint32_t, avgRowPerSubCore); | ||
| 26 | +TILING_DATA_FIELD_DEF(uint32_t, preActiveSubCoreNum); | ||
| 27 | +END_TILING_DATA_DEF; | ||
| 28 | +REGISTER_TILING_DATA_CLASS(BsaMask2IdxTilingOp, BsaMask2IdxTiling) | ||
| 29 | +// attention tile info | ||
| 30 | +BEGIN_TILING_DATA_DEF(BsaBaseTiling) | ||
| 31 | +TILING_DATA_FIELD_DEF(uint32_t, qBaseTile); | ||
| 32 | +TILING_DATA_FIELD_DEF(uint32_t, kvBaseTile); | ||
| 33 | +END_TILING_DATA_DEF; | ||
| 34 | +REGISTER_TILING_DATA_CLASS(BsaBaseTilingOp, BsaBaseTiling) | ||
| 35 | +// matmul phase L1 tile info | ||
| 36 | +BEGIN_TILING_DATA_DEF(BsaMmPhaseL1Tiling) | ||
| 37 | +TILING_DATA_FIELD_DEF(uint32_t, mm1L1TileM); | ||
| 38 | +TILING_DATA_FIELD_DEF(uint32_t, mm1L1TileN); | ||
| 39 | +TILING_DATA_FIELD_DEF(uint32_t, mm1L1TileKLeft); | ||
| 40 | +TILING_DATA_FIELD_DEF(uint32_t, mm1L1TileKRight); | ||
| 41 | +TILING_DATA_FIELD_DEF(uint32_t, mm2L1TileM); | ||
| 42 | +TILING_DATA_FIELD_DEF(uint32_t, mm2L1TileN); | ||
| 43 | +TILING_DATA_FIELD_DEF(uint32_t, mm2L1TileKLeft); | ||
| 44 | +TILING_DATA_FIELD_DEF(uint32_t, mm2L1TileKRight); | ||
| 45 | +TILING_DATA_FIELD_DEF(uint32_t, qL1BufNum); | ||
| 46 | +TILING_DATA_FIELD_DEF(uint32_t, kL1BufNum); | ||
| 47 | +TILING_DATA_FIELD_DEF(uint32_t, vL1BufNum); | ||
| 48 | +TILING_DATA_FIELD_DEF(uint32_t, pL1BufNum); | ||
| 49 | +END_TILING_DATA_DEF; | ||
| 50 | +REGISTER_TILING_DATA_CLASS(BsaMmPhaseL1TilingOp, BsaMmPhaseL1Tiling) | ||
| 51 | +// EagleQuantBlockSparseAttention Tiling数据定义 | ||
| 52 | +BEGIN_TILING_DATA_DEF(EagleQuantBlockSparseAttentionTilingData) | ||
| 53 | +// 基础参数 | ||
| 54 | +TILING_DATA_FIELD_DEF(uint32_t, batch); | ||
| 55 | +TILING_DATA_FIELD_DEF(uint32_t, numHeads); | ||
| 56 | +TILING_DATA_FIELD_DEF(uint32_t, kvHeads); | ||
| 57 | +TILING_DATA_FIELD_DEF(uint32_t, embeddingSize); | ||
| 58 | +TILING_DATA_FIELD_DEF(uint32_t, blockSize); | ||
| 59 | +TILING_DATA_FIELD_DEF(uint32_t, maxNumBlocksPerBatch); | ||
| 60 | +TILING_DATA_FIELD_DEF(uint32_t, firstBatchTaskNum); | ||
| 61 | +TILING_DATA_FIELD_DEF(uint32_t, totalTaskNum); | ||
| 62 | +TILING_DATA_FIELD_DEF(uint32_t, maskType); | ||
| 63 | +TILING_DATA_FIELD_DEF(float, scaleValue); | ||
| 64 | +TILING_DATA_FIELD_DEF(uint32_t, totalQBlocks); // T: 所有batch中Q方向切块的总数 | ||
| 65 | +TILING_DATA_FIELD_DEF(uint32_t, firstQBlockNum); // T: 所有batch中Q方向切块的总数 | ||
| 66 | + | ||
| 67 | +// 稀疏分块参数 (blockShape) | ||
| 68 | +TILING_DATA_FIELD_DEF(uint64_t, blockShapeX); // block的x维度(Q方向) | ||
| 69 | +TILING_DATA_FIELD_DEF(uint64_t, blockShapeY); // block的y维度(KV方向) | ||
| 70 | + | ||
| 71 | +// selectIdx相关参数 | ||
| 72 | +TILING_DATA_FIELD_DEF(uint32_t, maxKvBlockNum); // 最大KV块数量(selectIdx的最后一维) | ||
| 73 | +TILING_DATA_FIELD_DEF(uint32_t, maxQBlockNum); // 最大KV块数量(selectIdx的最后一维) | ||
| 74 | +TILING_DATA_FIELD_DEF(uint32_t, avgRowNumPerSubCore); | ||
| 75 | +TILING_DATA_FIELD_DEF(uint32_t, preActivateSubCoreNum); | ||
| 76 | + | ||
| 77 | + | ||
| 78 | +// query Layout: 0=TND, 1=BNSD | ||
| 79 | +TILING_DATA_FIELD_DEF(uint32_t, queryLayout); | ||
| 80 | + | ||
| 81 | +// KV Cache Layout: 0=TND, 1=BNSD | ||
| 82 | +TILING_DATA_FIELD_DEF(uint32_t, kvCacheLayout); | ||
| 83 | + | ||
| 84 | +// BNSD格式的最大序列长度(用于计算stride) | ||
| 85 | +// 当actualSeqLengths为nullptr时,maxQSeqlen也用作统一的qseqlen值 | ||
| 86 | +TILING_DATA_FIELD_DEF(uint32_t, maxQSeqlen); // BNSD格式Q的第三维(S维度),或统一的qseqlen值 | ||
| 87 | +// 当actualSeqLengthsKv为nullptr时,maxKvSeqlen也用作统一的kvseqlen值 | ||
| 88 | +TILING_DATA_FIELD_DEF(uint32_t, maxKvSeqlen); // BNSD格式KV的第三维(S维度),或统一的kvseqlen值 | ||
| 89 | +TILING_DATA_FIELD_DEF(uint32_t, useUniformQSeqlen); // 是否使用统一的qseqlen值(1=是,0=否) | ||
| 90 | +TILING_DATA_FIELD_DEF(uint32_t, useUniformKvSeqlen); // 是否使用统一的kvseqlen值(1=是,0=否) | ||
| 91 | + | ||
| 92 | +// TilingKey for kernel dispatch (生成在tiling层) | ||
| 93 | +TILING_DATA_FIELD_DEF(uint64_t, tilingKey); | ||
| 94 | +TILING_DATA_FIELD_DEF(uint64_t, selectNumIdxSize); | ||
| 95 | +TILING_DATA_FIELD_DEF(uint64_t, selectIdxSize); | ||
| 96 | +// Workspace大小 | ||
| 97 | +TILING_DATA_FIELD_DEF(uint64_t, mm1OutSize); | ||
| 98 | +TILING_DATA_FIELD_DEF(uint64_t, smOnlineOutSize); | ||
| 99 | +TILING_DATA_FIELD_DEF(uint64_t, mm2OutSize); | ||
| 100 | +TILING_DATA_FIELD_DEF(uint64_t, updateSize); | ||
| 101 | +TILING_DATA_FIELD_DEF(uint64_t, workSpaceSize); | ||
| 102 | + | ||
| 103 | +TILING_DATA_FIELD_DEF_STRUCT(BsaMask2IdxTiling, BsaMask2IdxTileInfo); | ||
| 104 | +TILING_DATA_FIELD_DEF_STRUCT(BsaBaseTiling, BsaBaseTileInfo); | ||
| 105 | +TILING_DATA_FIELD_DEF_STRUCT(BsaMmPhaseL1Tiling, BsaMmPhaseL1TileInfo); | ||
| 106 | +TILING_DATA_FIELD_DEF(uint32_t, sparsePatternMode); | ||
| 107 | +END_TILING_DATA_DEF; | ||
| 108 | +REGISTER_TILING_DATA_CLASS(EagleQuantBlockSparseAttention, EagleQuantBlockSparseAttentionTilingData) | ||
| 109 | + | ||
| 110 | +// EagleQuantBlockSparseAttention编译信息 | ||
| 111 | +struct EagleQuantBlockSparseAttentionCompileInfo { | ||
| 112 | + uint32_t inputDataByte = 2; | ||
| 113 | + ge::DataType inputDataType; | ||
| 114 | + | ||
| 115 | + uint32_t coreNum = 0; | ||
| 116 | + uint32_t aivNum = 0; | ||
| 117 | + uint32_t aicNum = 0; | ||
| 118 | + uint64_t ubSize = 0; | ||
| 119 | + uint64_t l1Size = 0; | ||
| 120 | + uint64_t sysWorkspaceSize = 0; | ||
| 121 | + platform_ascendc::SocVersion socVersion; | ||
| 122 | +}; | ||
| 123 | + | ||
| 124 | +// 输入参数信息 | ||
| 125 | +struct RequiredParaInfo { | ||
| 126 | + const gert::CompileTimeTensorDesc *desc; | ||
| 127 | + const gert::StorageShape *shape; | ||
| 128 | +}; | ||
| 129 | + | ||
| 130 | +struct OptionalParaInfo { | ||
| 131 | + const gert::CompileTimeTensorDesc *desc; | ||
| 132 | + const gert::Tensor *tensor; | ||
| 133 | +}; | ||
| 134 | + | ||
| 135 | +// KVCache Layout枚举 | ||
| 136 | +enum RFAKvCacheLayout : uint32_t { | ||
| 137 | + TND = 0, // [T, N, D] format | ||
| 138 | + BNSD = 1 // [B, N, S, D] format | ||
| 139 | +}; | ||
| 140 | + | ||
| 141 | +// Q Input Layout枚举 | ||
| 142 | +enum RFAQInputLayout : uint32_t { | ||
| 143 | + TND_Q = 0, // [T, N, D] format | ||
| 144 | + BNSD_Q = 1 // [B, N, S, D] format | ||
| 145 | +}; | ||
| 146 | + | ||
| 147 | +// inner prec 枚举 | ||
| 148 | +enum BsaInnerCalcPrec : uint32_t { | ||
| 149 | + ALL_HIGH = 0, | ||
| 150 | + ALL_LOW = 1, | ||
| 151 | + LOW_HIGH_MIXED = 4 | ||
| 152 | +}; | ||
| 153 | + | ||
| 154 | +// Tiling类 | ||
| 155 | +class BSATiling { | ||
| 156 | +public: | ||
| 157 | + BSATiling() = default; | ||
| 158 | + ~BSATiling() = default; | ||
| 159 | + | ||
| 160 | + ge::graphStatus GetBsaTiling(gert::TilingContext *bsaContext, | ||
| 161 | + EagleQuantBlockSparseAttentionTilingData &tilingData); | ||
| 162 | + ge::graphStatus BsaSetTilingData(gert::TilingContext *context, | ||
| 163 | + EagleQuantBlockSparseAttentionTilingData &tilingData); | ||
| 164 | + | ||
| 165 | +private: | ||
| 166 | + ge::graphStatus GetNpuInfo(gert::TilingContext *bsaContext); | ||
| 167 | + ge::graphStatus ParseAttrs(gert::TilingContext *bsaContext); | ||
| 168 | + ge::graphStatus GetInputLayout(gert::TilingContext *bsaContext); | ||
| 169 | + ge::graphStatus ParseRequiredTensors(gert::TilingContext *bsaContext); | ||
| 170 | + ge::graphStatus ParseOptionalTensors(gert::TilingContext *bsaContext); | ||
| 171 | + ge::graphStatus CheckQKVDtype(gert::TilingContext *bsaContext); | ||
| 172 | + ge::graphStatus CheckQKVDimVal(gert::TilingContext *bsaContext, | ||
| 173 | + uint32_t kHeads, uint32_t vHeads, uint32_t kHeadDim, uint32_t vHeadDim); | ||
| 174 | + ge::graphStatus ParseQKVInTND(gert::TilingContext *bsaContext); | ||
| 175 | + ge::graphStatus ParseQKVInBNSD(gert::TilingContext *bsaContext); | ||
| 176 | + ge::graphStatus ParseSeqlensInTND(gert::TilingContext *bsaContext); | ||
| 177 | + ge::graphStatus ParseSeqlensInBNSD(gert::TilingContext *bsaContext); | ||
| 178 | + ge::graphStatus ParseSeqlens(gert::TilingContext *bsaContext); | ||
| 179 | + ge::graphStatus ParseSparsePattern(gert::TilingContext *bsaContext); | ||
| 180 | + ge::graphStatus ParseAttenMask(gert::TilingContext *bsaContext); | ||
| 181 | + ge::graphStatus ParseBlockTable(gert::TilingContext *bsaContext); | ||
| 182 | + ge::graphStatus CheckSparsePattern(gert::TilingContext *bsaContext, const int64_t defaultShape); | ||
| 183 | + ge::graphStatus ValidateTNDSeqlenSum(gert::TilingContext *bsaContext); | ||
| 184 | + // 950 exclusive | ||
| 185 | + uint32_t GetCurQSTileNum950(int64_t curQSeqlen); | ||
| 186 | + void CalcBaseTileTilingParams950(); | ||
| 187 | + void CalcSplitCoreTilingParams950(); | ||
| 188 | + void CalcWorkspaceTilingParams950(gert::TilingContext *bsaContext); | ||
| 189 | + void CalcMatmulPhaseL1TileInfo950(); | ||
| 190 | + // 910 exclusive | ||
| 191 | + ge::graphStatus CalculateTaskSplit(gert::TilingContext *bsaContext); | ||
| 192 | + ge::graphStatus CalculateWorkSpace(gert::TilingContext *bsaContext); | ||
| 193 | + // shared | ||
| 194 | + void CalculateBatchTaskSplit(int64_t qSeqlen, uint32_t groupSize, | ||
| 195 | + uint32_t &curTaskNum, uint32_t &curQBlockNum); | ||
| 196 | + ge::graphStatus FillTilingData(gert::TilingContext *bsaContext); | ||
| 197 | + uint64_t GenerateTilingKey(gert::TilingContext *bsaContext); | ||
| 198 | + | ||
| 199 | +private: | ||
| 200 | + uint32_t batch_ = 0; | ||
| 201 | + uint32_t qSeqlen_ = 0; | ||
| 202 | + uint32_t kvSeqlen_ = 0; | ||
| 203 | + uint32_t numHeads_ = 0; | ||
| 204 | + uint32_t kvHeads_ = 0; | ||
| 205 | + uint32_t embeddingSize_ = 0; | ||
| 206 | + uint32_t blockSize_ = 128; | ||
| 207 | + int64_t blockShapeX_ = 0; // block的x维度 | ||
| 208 | + int64_t blockShapeY_ = 0; // block的y维度 | ||
| 209 | + float scaleValue_ = 0.0f; | ||
| 210 | + uint32_t maskType_ = 0; | ||
| 211 | + uint32_t sparsePatternMode_ = 0; | ||
| 212 | + uint32_t innerPrecise_ = 1; // 0=float32 softmax, 1=fp16 softmax | ||
| 213 | + bool softmaxLseFlag_ = false; | ||
| 214 | + | ||
| 215 | + uint32_t totalQBlocks_ = 0; | ||
| 216 | + uint32_t maxKvBlockNum_ = 0; | ||
| 217 | + uint32_t maxQBlockNum_ = 0; | ||
| 218 | + uint32_t avgRowNumPerSubCore_ = 0; | ||
| 219 | + uint32_t preActivateSubCoreNum_ = 0; | ||
| 220 | + uint32_t firstQBlockNum_ = 0; | ||
| 221 | + uint32_t firstBatchTaskNum_ = 0; | ||
| 222 | + uint32_t totalTaskNum_ = 0; | ||
| 223 | + uint32_t maxNumBlocksPerBatch_ = 0; | ||
| 224 | + const int64_t *qSeqLenList_ = nullptr; | ||
| 225 | + const int64_t *kvSeqLenList_ = nullptr; | ||
| 226 | + const int64_t *blockShapeList = nullptr; | ||
| 227 | + bool useUniformQSeqlen_ = false; // 是否使用统一的qseqlen值(使用maxQSeqlen_) | ||
| 228 | + bool useUniformKvSeqlen_ = false; // 是否使用统一的kvseqlen值(使用maxKvSeqlen_) | ||
| 229 | + | ||
| 230 | + uint64_t mm1OutSize_ = 0; | ||
| 231 | + uint64_t smOnlineOutSize_ = 0; | ||
| 232 | + uint64_t mm2OutSize_ = 0; | ||
| 233 | + uint64_t updateSize_ = 0; | ||
| 234 | + uint64_t selectNumIdxSize_ = 0; | ||
| 235 | + uint64_t selectIdxSize_ = 0; | ||
| 236 | + | ||
| 237 | + RFAKvCacheLayout kvCacheLayout_ = RFAKvCacheLayout::TND; | ||
| 238 | + RFAQInputLayout qInputLayout_ = RFAQInputLayout::TND_Q; | ||
| 239 | + | ||
| 240 | + uint32_t blockDim_ = 20; | ||
| 241 | + uint32_t aivNum_ = 0; | ||
| 242 | + uint32_t aicNum_ = 0; | ||
| 243 | + uint32_t socVer_ = 0; | ||
| 244 | + uint64_t ubSize_ = 0; | ||
| 245 | + uint64_t workSpaceSize_ = 0; | ||
| 246 | + uint64_t libapiSize_ = 0; | ||
| 247 | + | ||
| 248 | + uint32_t maxQSeqlen_ = 0; // BNSD格式Q的第三维(S维度) | ||
| 249 | + uint32_t maxKvSeqlen_ = 0; // BNSD格式KV的第三维(S维度) | ||
| 250 | + int64_t totalTokensT_ = 0; // TND格式Q的第一维(T维度,总token数) | ||
| 251 | + int64_t totalTokensKv_ = 0; // TND格式KV的第一维(T维度,总token数 | ||
| 252 | + | ||
| 253 | + // mask2idx tile info | ||
| 254 | + uint32_t xBlockNumAligned_; | ||
| 255 | + uint32_t yBlockNumAligned_; | ||
| 256 | + uint32_t avgRowPerSubCore_; | ||
| 257 | + uint32_t preActiveSubCoreNum_; | ||
| 258 | + // base tile info | ||
| 259 | + uint32_t qBaseTile_; | ||
| 260 | + uint32_t kvBaseTile_; | ||
| 261 | + // L1 tile info | ||
| 262 | + // further splits the base tiles | ||
| 263 | + uint32_t mm1L1TileM_; | ||
| 264 | + uint32_t mm1L1TileN_; | ||
| 265 | + uint32_t mm1L1TileKLeft_; | ||
| 266 | + uint32_t mm1L1TileKRight_; | ||
| 267 | + uint32_t mm2L1TileM_; | ||
| 268 | + uint32_t mm2L1TileN_; | ||
| 269 | + uint32_t mm2L1TileKLeft_; | ||
| 270 | + uint32_t mm2L1TileKRight_; | ||
| 271 | + uint32_t qL1BufNum_; | ||
| 272 | + uint32_t kL1BufNum_; | ||
| 273 | + uint32_t vL1BufNum_; | ||
| 274 | + uint32_t pL1BufNum_; | ||
| 275 | + | ||
| 276 | + ge::DataType dataType_ = ge::DT_FLOAT16; | ||
| 277 | + // 在 dataType_ 声明附近添加: | ||
| 278 | + ge::DataType vDataType_ = ge::DT_FLOAT16; // 新增:记录V的独立dtype | ||
| 279 | + | ||
| 280 | + EagleQuantBlockSparseAttentionTilingData *tilingData_ = nullptr; | ||
| 281 | +}; | ||
| 282 | + | ||
| 283 | +} // namespace optiling | ||
| 284 | + | ||
| 285 | + | ||
| 286 | + | ||
| @@ -0,0 +1,799 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +using namespace NpuArch; | ||
| 17 | +using namespace tla; | ||
| 18 | + | ||
| 19 | +namespace BsaKernelArch35 { | ||
| 20 | + | ||
| 21 | +template < | ||
| 22 | + class EpilogueMask2Idx, | ||
| 23 | + class QKL1TileShape, | ||
| 24 | + class QKL0TileShape, | ||
| 25 | + class ElementS_, | ||
| 26 | + class QKBias, | ||
| 27 | + class QKTileCopy, | ||
| 28 | + class QKTileMmad, | ||
| 29 | + class EpilogueOnlineSoftmax, | ||
| 30 | + class PVL1TileShape, | ||
| 31 | + class PVL0TileShape, | ||
| 32 | + class ElementOTmp_, | ||
| 33 | + class PVBias, | ||
| 34 | + class PVTileCopy, | ||
| 35 | + class PVTileMmad, | ||
| 36 | + class EpilogueRescaleO, | ||
| 37 | + Format qFormat, | ||
| 38 | + Format kvFormat> | ||
| 39 | +class BsaRegularKernelArch35< | ||
| 40 | + EpilogueMask2Idx, | ||
| 41 | + Gemm::Block::BlockMmadTla<Gemm::MmadAtlasA5BsaQK, QKL1TileShape, QKL0TileShape, | ||
| 42 | + int8_t, int8_t, ElementS_, QKBias, QKTileCopy, QKTileMmad>, | ||
| 43 | + EpilogueOnlineSoftmax, | ||
| 44 | + Gemm::Block::BlockMmadTla<Gemm::MmadAtlasA5BsaPV, PVL1TileShape, PVL0TileShape, | ||
| 45 | + float8_e4m3_t, float8_e4m3_t, ElementOTmp_, PVBias, PVTileCopy, PVTileMmad>, | ||
| 46 | + EpilogueRescaleO, | ||
| 47 | + qFormat, | ||
| 48 | + kvFormat> { | ||
| 49 | +public: | ||
| 50 | + using BlockMmadQK = Gemm::Block::BlockMmadTla<Gemm::MmadAtlasA5BsaQK, QKL1TileShape, QKL0TileShape, | ||
| 51 | + int8_t, int8_t, ElementS_, QKBias, QKTileCopy, QKTileMmad>; | ||
| 52 | + using BlockMmadPV = Gemm::Block::BlockMmadTla<Gemm::MmadAtlasA5BsaPV, PVL1TileShape, PVL0TileShape, | ||
| 53 | + float8_e4m3_t, float8_e4m3_t, ElementOTmp_, PVBias, PVTileCopy, PVTileMmad>; | ||
| 54 | + using ArchTag = typename BlockMmadPV::ArchTag; | ||
| 55 | + | ||
| 56 | + using ElementQ = typename BlockMmadQK::ElementA; | ||
| 57 | + using ElementK = typename BlockMmadQK::ElementB; | ||
| 58 | + using ElementS = typename EpilogueOnlineSoftmax::ElementInput; | ||
| 59 | + using ElementP = typename BlockMmadPV::ElementA; | ||
| 60 | + using ElementV = typename BlockMmadPV::ElementB; | ||
| 61 | + using ElementOTmp = typename BlockMmadPV::ElementC; | ||
| 62 | + using ElementO = typename EpilogueRescaleO::ElementO; | ||
| 63 | + using ElementSparseMask = typename EpilogueMask2Idx::ElementSparseMask; | ||
| 64 | + using ElementSparseIdx = typename EpilogueMask2Idx::ElementSparseIdx; | ||
| 65 | + using ElementSparseCount = typename EpilogueMask2Idx::ElementSparseCount; | ||
| 66 | + | ||
| 67 | + using LayoutQ = layout::ColumnMajor; | ||
| 68 | + using LayoutK = layout::RowMajor; | ||
| 69 | + //qmode为1的时候设置为RowMajor,原本是Q*KT,现在改成了(K * QT)T,所以LayoutS是RowMajor | ||
| 70 | + using LayoutS = layout::RowMajor; | ||
| 71 | + using LayoutP = layout::RowMajor; | ||
| 72 | + using LayoutV = layout::RowMajor; | ||
| 73 | + using LayoutO = layout::RowMajor; | ||
| 74 | + using LayoutOTmp = layout::RowMajor; | ||
| 75 | + using LayoutSparseIdx = layout::RowMajor; | ||
| 76 | + using LayoutSparseCount = layout::RowMajor; | ||
| 77 | + | ||
| 78 | + using LayoutTagL1P = typename BlockMmadPV::LayoutTagL1A; | ||
| 79 | + | ||
| 80 | + static constexpr uint32_t PRE_LAUNCH = 2; | ||
| 81 | + static constexpr uint32_t MAX_CROSS_CORE_BUF_STAGES = PRE_LAUNCH + 1; | ||
| 82 | + static constexpr uint32_t UB_S_OTMP_BUF_STAGES = 2; | ||
| 83 | + static constexpr uint32_t QUANT_BLOCK_SIZE = 64; | ||
| 84 | + | ||
| 85 | + // Methods | ||
| 86 | + __aicore__ inline | ||
| 87 | + BsaRegularKernelArch35() {} | ||
| 88 | + | ||
| 89 | + __aicore__ inline | ||
| 90 | + int GetQkStaticLoopNum() | ||
| 91 | + { | ||
| 92 | + return ((qBaseTile_ == BlockMmadQK::L0_TILE_M) && | ||
| 93 | + (embed_ == BlockMmadQK::L0_TILE_K) && | ||
| 94 | + ((kvBaseTile_ == BlockMmadQK::L0_TILE_N) || | ||
| 95 | + (kvBaseTile_ == BlockMmadQK::L0_TILE_N * 2U))) ? | ||
| 96 | + 1 : Gemm::Block::Arch35MmadOpt::DYNAMIC_LOOP; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + __aicore__ inline | ||
| 100 | + int GetPvStaticNLoopNum() | ||
| 101 | + { | ||
| 102 | + if (qBaseTile_ != BlockMmadPV::L0_TILE_M) { | ||
| 103 | + return Gemm::Block::Arch35MmadOpt::DYNAMIC_LOOP; | ||
| 104 | + } | ||
| 105 | + if (embed_ == BlockMmadPV::L0_TILE_N) { | ||
| 106 | + return 1; | ||
| 107 | + } | ||
| 108 | + if (embed_ == BlockMmadPV::L0_TILE_N * 2U) { | ||
| 109 | + return 2; | ||
| 110 | + } | ||
| 111 | + return Gemm::Block::Arch35MmadOpt::DYNAMIC_LOOP; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + template<int quant_mode=1> | ||
| 115 | + __aicore__ inline | ||
| 116 | + void operator()(BsaKernelParamsArch35 const ¶ms) | ||
| 117 | + { | ||
| 118 | + static_assert(quant_mode == 1); | ||
| 119 | + __gm__ EagleQuantBlockSparseAttentionTilingData *bsaTilingData = | ||
| 120 | + reinterpret_cast<__gm__ EagleQuantBlockSparseAttentionTilingData *>(params.tiling); | ||
| 121 | + FetchBaseShapeInfo(bsaTilingData); | ||
| 122 | + CalcOnChipBufTileInfo(bsaTilingData); | ||
| 123 | + // global buffers | ||
| 124 | + AscendC::GlobalTensor<ElementQ> gQ; | ||
| 125 | + gQ.SetGlobalBuffer((__gm__ ElementQ *)params.q); | ||
| 126 | + AscendC::GlobalTensor<ElementK> gK; | ||
| 127 | + gK.SetGlobalBuffer((__gm__ ElementK *)params.k); | ||
| 128 | + AscendC::GlobalTensor<ElementV> gV; | ||
| 129 | + gV.SetGlobalBuffer((__gm__ ElementV *)params.v); | ||
| 130 | + AscendC::GlobalTensor<int64_t> gActualQseqlen; | ||
| 131 | + gActualQseqlen.SetGlobalBuffer((__gm__ int64_t *)params.actualQseqlen); | ||
| 132 | + AscendC::GlobalTensor<int64_t> gActualKvseqlen; | ||
| 133 | + gActualKvseqlen.SetGlobalBuffer((__gm__ int64_t *)params.actualKvseqlen); | ||
| 134 | + AscendC::GlobalTensor<uint8_t> gBlockSparseMask; | ||
| 135 | + gBlockSparseMask.SetGlobalBuffer((__gm__ uint8_t *)params.blockSparseMask); | ||
| 136 | + AscendC::GlobalTensor<ElementO> gO; | ||
| 137 | + gO.SetGlobalBuffer((__gm__ ElementO *)params.o); | ||
| 138 | + AscendC::GlobalTensor<ElementSparseIdx> gSparseIdx; | ||
| 139 | + if (bsaTilingData->sparsePatternMode == SPARSE_PATTERN_MODE_TABLE) { | ||
| 140 | + gSparseIdx.SetGlobalBuffer((__gm__ ElementSparseIdx *)params.blockSparseMask); | ||
| 141 | + } else { | ||
| 142 | + gSparseIdx.SetGlobalBuffer((__gm__ ElementSparseIdx *)params.workSpace); | ||
| 143 | + } | ||
| 144 | + AscendC::GlobalTensor<ElementSparseCount> gSparseCount; | ||
| 145 | + gSparseCount.SetGlobalBuffer((__gm__ ElementSparseCount *)(params.workSpace + sparseIdxSize_)); | ||
| 146 | + AscendC::GlobalTensor<float> queryScale; | ||
| 147 | + queryScale.SetGlobalBuffer((__gm__ float *)(params.query_scale)); | ||
| 148 | + AscendC::GlobalTensor<float> keyScale; | ||
| 149 | + keyScale.SetGlobalBuffer((__gm__ float *)(params.key_scale)); | ||
| 150 | + AscendC::GlobalTensor<float> valueScale; | ||
| 151 | + valueScale.SetGlobalBuffer((__gm__ float *)(params.value_scale)); | ||
| 152 | + | ||
| 153 | + // cross core data move dst buffers | ||
| 154 | + AscendC::LocalTensor<ElementP> l1PTensor[MAX_CROSS_CORE_BUF_STAGES]; | ||
| 155 | + AscendC::LocalTensor<ElementS> ubSTensor[UB_S_OTMP_BUF_STAGES]; | ||
| 156 | + AscendC::LocalTensor<ElementOTmp> ubOTmpTensor[UB_S_OTMP_BUF_STAGES]; | ||
| 157 | + InitCrossCoreDstBuf(l1PTensor, ubSTensor, ubOTmpTensor); | ||
| 158 | + // core idx | ||
| 159 | + uint32_t coreIdx = AscendC::GetBlockIdx(); | ||
| 160 | + uint32_t coreNum = AscendC::GetBlockNum(); | ||
| 161 | + // set reverse sync flags | ||
| 162 | + InitSyncFlags<4, 4, 4>(); | ||
| 163 | + | ||
| 164 | + uint32_t totalRowNumBlockMask = batch_ * qHeads_ * xBlockNumAligned_; | ||
| 165 | + if (bsaTilingData->sparsePatternMode == SPARSE_PATTERN_MODE_TABLE) { | ||
| 166 | + //AscendC::printf("good job\n"); | ||
| 167 | + SparseTable2Count(resource, gSparseIdx, gSparseCount, | ||
| 168 | + totalRowNumBlockMask, yBlockNumAligned_, avgRowPerSubCore_, preActiveSubCoreNum_); | ||
| 169 | + } else { | ||
| 170 | + EpilogueMask2Idx epilogueMask2Idx(resource); | ||
| 171 | + epilogueMask2Idx( | ||
| 172 | + gBlockSparseMask, gSparseIdx, gSparseCount, | ||
| 173 | + totalRowNumBlockMask, yBlockNumAligned_, avgRowPerSubCore_, preActiveSubCoreNum_); | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + AscendC::SyncAll<false>(); | ||
| 177 | + | ||
| 178 | + coreIdx = AscendC::GetBlockIdx(); | ||
| 179 | + BlockMmadQK blockMmadQK(resource, mm1L1TileHelper_); | ||
| 180 | + BlockMmadPV blockMmadPV(resource, mm2L1AddrStart_, mm2L1TileHelper_); | ||
| 181 | + | ||
| 182 | + | ||
| 183 | + coreIdx = AscendC::GetBlockIdx() / AscendC::GetSubBlockNum(); | ||
| 184 | + EpilogueOnlineSoftmax epilogueOnlineSoftmax(resource, scaleValue_, blockShapeY_); | ||
| 185 | + EpilogueRescaleO epilogueRescaleO(resource, embed_); | ||
| 186 | + auto scaleTensor = resource.ubBuf.template GetBufferByByte<float>(7 * 32 * 1024 + 4096 * 2); | ||
| 187 | + | ||
| 188 | + uint32_t qSTileNumPerFullXBlock = CeilDiv(blockShapeX_, qBaseTile_); | ||
| 189 | + // Calculate strides based on layout | ||
| 190 | + // For TND: [T, N, D], stride = N * D | ||
| 191 | + // For BNSD: [B, N, S, D], strideB = N * S * D, strideN = S * D, strideS = D | ||
| 192 | + int64_t strideQO = 0; | ||
| 193 | + int64_t strideKV = 0; | ||
| 194 | + int64_t strideQOB = 0; // BNSD batch_ stride for Q | ||
| 195 | + int64_t strideQON = 0; // BNSD head stride for Q | ||
| 196 | + int64_t strideQOS = 0; // BNSD seq stride for Q | ||
| 197 | + int64_t strideKVB = 0; // BNSD batch_ stride for KV | ||
| 198 | + int64_t strideKVN = 0; // BNSD head stride for KV | ||
| 199 | + int64_t strideKVS = 0; // BNSD seq stride for KV | ||
| 200 | + if constexpr (qFormat == Format::BNSD) { | ||
| 201 | + strideQOB = qHeads_ * qSeqlenAligned_ * embed_; // batch_ stride | ||
| 202 | + strideQON = qSeqlenAligned_ * embed_; // head stride | ||
| 203 | + strideQOS = embed_; // seq stride | ||
| 204 | + } else if constexpr (qFormat == Format::TND) { | ||
| 205 | + strideQO = qHeads_ * embed_; | ||
| 206 | + } | ||
| 207 | + if constexpr (kvFormat == Format::BNSD) { | ||
| 208 | + strideKVB = kvHeads_ * kvSeqlenAligned_ * embed_; // batch_ stride | ||
| 209 | + strideKVN = kvSeqlenAligned_ * embed_; // head stride | ||
| 210 | + strideKVS = embed_; // seq stride | ||
| 211 | + } else if constexpr (kvFormat == Format::TND) { | ||
| 212 | + strideKV = kvHeads_ * embed_; | ||
| 213 | + } | ||
| 214 | + uint32_t embedRound = RoundUp(embed_, 16); | ||
| 215 | + uint32_t groupSize = qHeads_ / kvHeads_; | ||
| 216 | + int qkStaticLoopNum = GetQkStaticLoopNum(); | ||
| 217 | + int pvStaticNLoopNum = GetPvStaticNLoopNum(); | ||
| 218 | + int64_t qBOffset = 0; | ||
| 219 | + int64_t kBOffset = 0; | ||
| 220 | + int64_t vBOffset = 0; | ||
| 221 | + int64_t oBOffset = 0; | ||
| 222 | + uint32_t preTotalTaskNum = 0; | ||
| 223 | + uint32_t curBatch = 0; | ||
| 224 | + int64_t qSeqlen = actSeqAval_ ? gActualQseqlen.GetValue(curBatch) : qSeqlenAligned_; | ||
| 225 | + int64_t kvSeqlen = actSeqAval_ ? gActualKvseqlen.GetValue(curBatch) : kvSeqlenAligned_; | ||
| 226 | + uint32_t curQSTileNum = GetCurQSTileNum(qSeqlen, blockShapeX_, qBaseTile_); | ||
| 227 | + uint32_t curTotalTaskNum = firstBatchTaskNum_; | ||
| 228 | + // Go through each task | ||
| 229 | + for (uint32_t taskIdx = coreIdx; taskIdx < totalTaskNum_; taskIdx += coreNum) { | ||
| 230 | + while (taskIdx >= curTotalTaskNum) { | ||
| 231 | + ++curBatch; | ||
| 232 | + preTotalTaskNum = curTotalTaskNum; | ||
| 233 | + if constexpr (qFormat == Format::TND) { | ||
| 234 | + qBOffset += qSeqlen * strideQO; | ||
| 235 | + oBOffset += qSeqlen * strideQO; | ||
| 236 | + } | ||
| 237 | + if constexpr (kvFormat == Format::TND) { | ||
| 238 | + kBOffset += kvSeqlen * strideKV; | ||
| 239 | + vBOffset += kvSeqlen * strideKV; | ||
| 240 | + } | ||
| 241 | + qSeqlen = actSeqAval_ ? gActualQseqlen.GetValue(curBatch) : qSeqlenAligned_; | ||
| 242 | + kvSeqlen = actSeqAval_ ? gActualKvseqlen.GetValue(curBatch) : kvSeqlenAligned_; | ||
| 243 | + curQSTileNum = GetCurQSTileNum(qSeqlen, blockShapeX_, qBaseTile_); | ||
| 244 | + curTotalTaskNum += curQSTileNum * qHeads_; | ||
| 245 | + } | ||
| 246 | + uint32_t taskIdxCurBatch = taskIdx - preTotalTaskNum; | ||
| 247 | + uint32_t qHeadIdx = taskIdxCurBatch / curQSTileNum; | ||
| 248 | + uint32_t kvHeadIdx = qHeadIdx / groupSize; | ||
| 249 | + uint32_t qSTileIdx = taskIdxCurBatch - qHeadIdx * curQSTileNum; | ||
| 250 | + // corresponding xBlock index of cur task | ||
| 251 | + uint32_t xBlockIdx = qSTileIdx / qSTileNumPerFullXBlock; | ||
| 252 | + // the q base tile index within the corrsponding xBlock of cur task | ||
| 253 | + uint32_t qSTileIdxCurXBlock = qSTileIdx - xBlockIdx * qSTileNumPerFullXBlock; | ||
| 254 | + // corresponding head index of cur task | ||
| 255 | + // corresponding blockSparseMask gm offset of cur task | ||
| 256 | + // gmBlockSparseMask has the shape [B, qN, xBlockNumAligned, yBlockNumAligned] | ||
| 257 | + int64_t sparseMaskBOffset = curBatch * qHeads_ * xBlockNumAligned_ * yBlockNumAligned_; | ||
| 258 | + int64_t sparseMaskNOffset = qHeadIdx * xBlockNumAligned_ * yBlockNumAligned_; | ||
| 259 | + int64_t sparseMaskXOffset = xBlockIdx * yBlockNumAligned_; | ||
| 260 | + int64_t gmOffsetSparseMask = sparseMaskBOffset + sparseMaskNOffset + sparseMaskXOffset; | ||
| 261 | + // corresponding Q/K/V/O gm offset of cur task | ||
| 262 | + int64_t gmOffsetQ = 0; | ||
| 263 | + int64_t gmOffsetK = 0; | ||
| 264 | + int64_t gmOffsetV = 0; | ||
| 265 | + int64_t gmOffsetO = 0; | ||
| 266 | + int64_t qSOffset = xBlockIdx * blockShapeX_ + qSTileIdxCurXBlock * qBaseTile_; | ||
| 267 | + if constexpr (qFormat == Format::BNSD) { | ||
| 268 | + qBOffset = curBatch * strideQOB; | ||
| 269 | + oBOffset = curBatch * strideQOB; | ||
| 270 | + gmOffsetQ = qBOffset + qHeadIdx * strideQON + qSOffset * strideQOS; | ||
| 271 | + gmOffsetO = oBOffset + qHeadIdx * strideQON + qSOffset * strideQOS; | ||
| 272 | + } else if constexpr (qFormat == Format::TND) { | ||
| 273 | + gmOffsetQ = qBOffset + qSOffset * strideQO + qHeadIdx * embed_; | ||
| 274 | + gmOffsetO = oBOffset + qSOffset * strideQO + qHeadIdx * embed_; | ||
| 275 | + } | ||
| 276 | + if constexpr (kvFormat == Format::BNSD) { | ||
| 277 | + kBOffset = curBatch * strideKVB; | ||
| 278 | + vBOffset = curBatch * strideKVB; | ||
| 279 | + gmOffsetK = kBOffset + kvHeadIdx * strideKVN; | ||
| 280 | + gmOffsetV = vBOffset + kvHeadIdx * strideKVN; | ||
| 281 | + } else if constexpr (kvFormat == Format::TND) { | ||
| 282 | + gmOffsetK = kBOffset + kvHeadIdx * embed_; | ||
| 283 | + gmOffsetV = vBOffset + kvHeadIdx * embed_; | ||
| 284 | + } | ||
| 285 | + // the actual x block num of cur batch_, calc by actual qseqlen | ||
| 286 | + uint32_t xBlockNumAval = static_cast<uint32_t>(CeilDiv(qSeqlen, static_cast<int64_t>(blockShapeX_))); | ||
| 287 | + uint32_t xBlockSize = (xBlockIdx == xBlockNumAval - 1) ? | ||
| 288 | + (qSeqlen - xBlockIdx * blockShapeX_) : blockShapeX_; | ||
| 289 | + uint32_t qSTileNumCurXBlock = CeilDiv(xBlockSize, qBaseTile_); | ||
| 290 | + uint32_t qSTileSizeAct = (qSTileIdxCurXBlock == qSTileNumCurXBlock - 1) ? | ||
| 291 | + (xBlockSize - qSTileIdxCurXBlock * qBaseTile_) : qBaseTile_; | ||
| 292 | + // calc the gathered kvS from sparse mask | ||
| 293 | + uint32_t gmOffsetSparseCount = | ||
| 294 | + curBatch * qHeads_ * xBlockNumAligned_ + qHeadIdx * xBlockNumAligned_ + xBlockIdx; | ||
| 295 | + uint32_t yBlockNumRsvd = gSparseCount.GetValue(gmOffsetSparseCount); | ||
| 296 | + if (yBlockNumRsvd == 0) { | ||
| 297 | + continue; | ||
| 298 | + } | ||
| 299 | + uint32_t gmOffsetSparseIdx = gmOffsetSparseCount * yBlockNumAligned_; | ||
| 300 | + uint32_t lastIdxOffset = gmOffsetSparseIdx + yBlockNumRsvd - 1; | ||
| 301 | + uint32_t lastSparseIdx = gSparseIdx.GetValue(lastIdxOffset); | ||
| 302 | + | ||
| 303 | + uint32_t yBlockNumAval = static_cast<uint32_t>(CeilDiv(kvSeqlen, static_cast<int64_t>(blockShapeY_))); | ||
| 304 | + uint32_t lastYBlockSize = (lastSparseIdx == yBlockNumAval - 1) ? | ||
| 305 | + kvSeqlen - lastSparseIdx * blockShapeY_ : blockShapeY_; | ||
| 306 | + int64_t gatheredKvSeqlen = (yBlockNumRsvd - 1) * blockShapeY_ + lastYBlockSize; | ||
| 307 | + // the rowNum of cur task | ||
| 308 | + // no qS*qN combination even in GQA/MQA senario, since each qN has a different sparse pattern | ||
| 309 | + uint32_t rowNum = qSTileSizeAct; | ||
| 310 | + uint32_t rowNumRound = RoundUp(rowNum, std::is_same_v<LayoutQ, layout::RowMajor> ? 16 : 64); | ||
| 311 | + uint32_t kvSLoopNum = static_cast<uint32_t>(CeilDiv(gatheredKvSeqlen, static_cast<int64_t>(kvBaseTile_))); | ||
| 312 | + uint32_t kvSTileSizeAct = kvBaseTile_; | ||
| 313 | + | ||
| 314 | + uint32_t kvShapeCol = 0; | ||
| 315 | + uint32_t qShapeCol = 0; | ||
| 316 | + if constexpr (qFormat == Format::BNSD) { | ||
| 317 | + qShapeCol = strideQOS; | ||
| 318 | + } else if constexpr (qFormat == Format::TND) { | ||
| 319 | + qShapeCol = strideQO; | ||
| 320 | + } | ||
| 321 | + if constexpr (kvFormat == Format::BNSD) { | ||
| 322 | + kvShapeCol = strideKVS; | ||
| 323 | + } else if constexpr (kvFormat == Format::TND) { | ||
| 324 | + kvShapeCol = strideKV; | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + GemmCoord actualBlockShapeQ{rowNum, embed_, 0}; | ||
| 328 | + if constexpr (std::is_same_v<LayoutQ, layout::RowMajor>) { | ||
| 329 | + auto gmQLayoutTla = tla::MakeLayout<ElementQ, LayoutQ>(qBaseTile_, qShapeCol); | ||
| 330 | + auto gmQTensorTla = tla::MakeTensor(gQ[gmOffsetQ], gmQLayoutTla, Arch::PositionGM{}); | ||
| 331 | + blockMmadQK.loadQGM(gmQTensorTla, actualBlockShapeQ); | ||
| 332 | + } else { | ||
| 333 | + auto gmQLayoutTla = tla::MakeLayout<ElementQ, LayoutQ>(qShapeCol, qBaseTile_); | ||
| 334 | + auto gmQTensorTla = tla::MakeTensor(gQ[gmOffsetQ], gmQLayoutTla, Arch::PositionGM{}); | ||
| 335 | + blockMmadQK.loadQGM(gmQTensorTla, actualBlockShapeQ); | ||
| 336 | + } | ||
| 337 | + | ||
| 338 | + auto gmKLayoutTla = tla::MakeLayout<ElementK, LayoutK>(kvSeqlenAligned_, kvShapeCol); | ||
| 339 | + auto gmKTensorTla = tla::MakeTensor(gK[gmOffsetK], gmKLayoutTla, Arch::PositionGM{}); | ||
| 340 | + | ||
| 341 | + auto gmVLayoutTla = tla::MakeLayout<ElementV, LayoutV>(kvBaseTile_, kvShapeCol); | ||
| 342 | + auto gmVTensorTla = tla::MakeTensor(gV[gmOffsetV], gmVLayoutTla, Arch::PositionGM{}); | ||
| 343 | + | ||
| 344 | + | ||
| 345 | + uint32_t oShapeCol = 0; | ||
| 346 | + if constexpr (qFormat == Format::BNSD) { | ||
| 347 | + oShapeCol = strideQOS; | ||
| 348 | + } else if constexpr (qFormat == Format::TND) { | ||
| 349 | + oShapeCol = strideQO; | ||
| 350 | + } | ||
| 351 | + | ||
| 352 | + for (uint32_t gatheredKvSTileIdx = 0; gatheredKvSTileIdx < kvSLoopNum + PRE_LAUNCH; gatheredKvSTileIdx++) { | ||
| 353 | + if (gatheredKvSTileIdx < kvSLoopNum) { | ||
| 354 | + if (gatheredKvSTileIdx == kvSLoopNum - 1) { | ||
| 355 | + kvSTileSizeAct = gatheredKvSeqlen - gatheredKvSTileIdx * kvBaseTile_; | ||
| 356 | + } else { | ||
| 357 | + kvSTileSizeAct = kvBaseTile_; | ||
| 358 | + } | ||
| 359 | + // QK | ||
| 360 | + GemmCoord actualBlockShapeQK{rowNum, kvSTileSizeAct, embed_}; | ||
| 361 | + uint32_t ubSBufId = gatheredKvSTileIdx % UB_S_OTMP_BUF_STAGES; | ||
| 362 | + auto ubSLayoutTla = tla::MakeLayout<ElementS, LayoutS>(RoundUp(kvSTileSizeAct, 16)*rowNumRound >> 5, 32); | ||
| 363 | + auto ubSTensorTla = tla::MakeTensor(ubSTensor[ubSBufId], | ||
| 364 | + ubSLayoutTla, Arch::PositionUB{}); | ||
| 365 | + uint32_t Mm1ToSmFlagId = ubSBufId; | ||
| 366 | + Arch::CrossCoreFlag mm1ToSmFlag(Mm1ToSmFlagId); | ||
| 367 | + | ||
| 368 | + uint64_t prefixSumL0AStages = CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 369 | + gatheredKvSTileIdx, mm1L0ATotalStages_, mm2L0ATotalStages_, kvSLoopNum, true); | ||
| 370 | + uint64_t prefixSumL0BStages = CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 371 | + gatheredKvSTileIdx, mm1L0BTotalStages_, mm2L0BTotalStages_, kvSLoopNum, true); | ||
| 372 | + if (qkStaticLoopNum == 1) { | ||
| 373 | + blockMmadQK.template operator()<quant_mode, 1, 1>( | ||
| 374 | + gmKTensorTla, ubSTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 375 | + actualBlockShapeQK, | ||
| 376 | + gatheredKvSTileIdx, kvSeqlen, | ||
| 377 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 378 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 379 | + mm1ToSmFlag, scaleValue_); | ||
| 380 | + } else { | ||
| 381 | + blockMmadQK.template operator()<quant_mode, -1, -1>( | ||
| 382 | + gmKTensorTla, ubSTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 383 | + actualBlockShapeQK, | ||
| 384 | + gatheredKvSTileIdx, kvSeqlen, | ||
| 385 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 386 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 387 | + mm1ToSmFlag, scaleValue_); | ||
| 388 | + } | ||
| 389 | + if (gatheredKvSTileIdx == kvSLoopNum - 1) | ||
| 390 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 391 | + | ||
| 392 | + // SM | ||
| 393 | + uint32_t l1PBufId = gatheredKvSTileIdx % pL1BufNum_; | ||
| 394 | + uint32_t smToMm2FlagId = l1PBufId + UB_S_OTMP_BUF_STAGES; | ||
| 395 | + Arch::CrossCoreFlag smToMm2Flag(smToMm2FlagId); | ||
| 396 | + auto l1PLayoutTla = tla::MakeLayout<ElementP, NpuArch::layout::zN>(rowNumRound, kvSTileSizeAct); | ||
| 397 | + auto l1PTensorTla = tla::MakeTensor(l1PTensor[l1PBufId], | ||
| 398 | + l1PLayoutTla, Arch::PositionL1{}); | ||
| 399 | + | ||
| 400 | + uint32_t qsOffset = 0; | ||
| 401 | + uint32_t ksOffset = 0; | ||
| 402 | + uint32_t vsOffset = curBatch * kvHeads_ * embed_ + kvHeadIdx * embed_; | ||
| 403 | + if (gatheredKvSTileIdx == 0) { | ||
| 404 | + AscendC::DataCopy(scaleTensor, valueScale[vsOffset], embed_); | ||
| 405 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID7); | ||
| 406 | + } | ||
| 407 | + if constexpr (qFormat == Format::BNSD) { | ||
| 408 | + uint32_t qScaleSeqNum = CeilDiv(qSeqlenAligned_,QUANT_BLOCK_SIZE); | ||
| 409 | + qsOffset = curBatch * qHeads_ * qScaleSeqNum + qHeadIdx * qScaleSeqNum + CeilDiv(qSOffset,QUANT_BLOCK_SIZE); | ||
| 410 | + } else if constexpr (qFormat == Format::TND) { | ||
| 411 | + qsOffset = CeilDiv((qBOffset / embed_), QUANT_BLOCK_SIZE) + CeilDiv(qSOffset, QUANT_BLOCK_SIZE) * qHeads_ + qHeadIdx; | ||
| 412 | + } | ||
| 413 | + if constexpr (kvFormat == Format::BNSD) { | ||
| 414 | + uint32_t kScaleSeqNum = CeilDiv(kvSeqlenAligned_, QUANT_BLOCK_SIZE); | ||
| 415 | + ksOffset = curBatch * kvHeads_ * kScaleSeqNum + kvHeadIdx * kScaleSeqNum; | ||
| 416 | + } else if constexpr (kvFormat == Format::TND) { | ||
| 417 | + ksOffset = CeilDiv(kBOffset / embed_, QUANT_BLOCK_SIZE) + kvHeadIdx; | ||
| 418 | + } | ||
| 419 | + uint32_t qScaleStride = (qFormat == Format::BNSD) ? 1 : qHeads_; | ||
| 420 | + uint32_t kScaleStride = (kvFormat == Format::BNSD) ? 1 : kvHeads_; | ||
| 421 | + auto gmQSLayoutTla = tla::MakeLayout<float, layout::RowMajor>( | ||
| 422 | + RoundUp(rowNum, QUANT_BLOCK_SIZE) / QUANT_BLOCK_SIZE, qScaleStride); | ||
| 423 | + auto gmQSTensorTla = tla::MakeTensor(queryScale[qsOffset], | ||
| 424 | + gmQSLayoutTla, Arch::PositionGM{}); | ||
| 425 | + auto gmKSLayoutTla = tla::MakeLayout<float, layout::RowMajor>( | ||
| 426 | + RoundUp(kvSeqlen, QUANT_BLOCK_SIZE) / QUANT_BLOCK_SIZE, kScaleStride); | ||
| 427 | + auto gmKSTensorTla = tla::MakeTensor(keyScale[ksOffset], | ||
| 428 | + gmKSLayoutTla, Arch::PositionGM{}); | ||
| 429 | + int32_t sparseTableStartOffset = gmOffsetSparseIdx + (gatheredKvSTileIdx) * (kvBaseTile_/blockShapeY_); | ||
| 430 | + epilogueOnlineSoftmax.template operator()<quant_mode>( | ||
| 431 | + l1PTensorTla, | ||
| 432 | + gmQSTensorTla, | ||
| 433 | + gmKSTensorTla, | ||
| 434 | + actualBlockShapeQK, | ||
| 435 | + (gatheredKvSTileIdx == 0), | ||
| 436 | + ubSBufId, | ||
| 437 | + l1PBufId, | ||
| 438 | + mm1ToSmFlag, | ||
| 439 | + smToMm2Flag, | ||
| 440 | + gSparseIdx[sparseTableStartOffset] | ||
| 441 | + ); | ||
| 442 | + if (gatheredKvSTileIdx == 0) { | ||
| 443 | + static constexpr float fp8MaxReciprocal = 1.0f / 448.0f; // exp((half)ln(448)) | ||
| 444 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID7); | ||
| 445 | + AscendC::Muls(scaleTensor[embed_], scaleTensor, fp8MaxReciprocal, embed_); | ||
| 446 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID7); | ||
| 447 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID7); | ||
| 448 | + } | ||
| 449 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 450 | + | ||
| 451 | + } | ||
| 452 | + if (gatheredKvSTileIdx >= PRE_LAUNCH) { | ||
| 453 | + uint32_t gatheredKvSTileIdxDe = gatheredKvSTileIdx - PRE_LAUNCH; | ||
| 454 | + if (gatheredKvSTileIdxDe == kvSLoopNum - 1) { | ||
| 455 | + kvSTileSizeAct = gatheredKvSeqlen - gatheredKvSTileIdxDe * kvBaseTile_; | ||
| 456 | + } else { | ||
| 457 | + kvSTileSizeAct = kvBaseTile_; | ||
| 458 | + } | ||
| 459 | + // PV | ||
| 460 | + GemmCoord actualBlockShapePV{rowNumRound, embed_, kvSTileSizeAct}; | ||
| 461 | + uint32_t ubOTmpBufId = gatheredKvSTileIdxDe % UB_S_OTMP_BUF_STAGES; | ||
| 462 | + // 核间同步flagId规律:每份dst对应一个id,从小到大顺序依次为qk->sm, sm->pv, pv->re | ||
| 463 | + uint32_t Mm2ToReFlagId = ubOTmpBufId + UB_S_OTMP_BUF_STAGES + pL1BufNum_; | ||
| 464 | + | ||
| 465 | + uint32_t l1PBufId = gatheredKvSTileIdxDe % pL1BufNum_; | ||
| 466 | + auto ubOTmpLayoutTla = tla::MakeLayout<ElementOTmp, LayoutOTmp>(rowNumRound, embedRound); | ||
| 467 | + auto ubOTmpTensorTla = tla::MakeTensor(ubOTmpTensor[ubOTmpBufId], | ||
| 468 | + ubOTmpLayoutTla, Arch::PositionUB{}); | ||
| 469 | + uint32_t smToMm2FlagId = l1PBufId + UB_S_OTMP_BUF_STAGES; | ||
| 470 | + | ||
| 471 | + Arch::CrossCoreFlag smToMm2Flag(smToMm2FlagId); | ||
| 472 | + Arch::CrossCoreFlag mm2ToReFlag(Mm2ToReFlagId); | ||
| 473 | + uint64_t prefixSumL0AStages = CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 474 | + gatheredKvSTileIdxDe, mm1L0ATotalStages_, mm2L0ATotalStages_, kvSLoopNum, false); | ||
| 475 | + uint64_t prefixSumL0BStages = CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 476 | + gatheredKvSTileIdxDe, mm1L0BTotalStages_, mm2L0BTotalStages_, kvSLoopNum, false); | ||
| 477 | + uint32_t vsOffset = curBatch * kvHeads_ * embed_ + kvHeadIdx * embed_; | ||
| 478 | + auto gmVSLayoutTla = tla::MakeLayout<float, layout::RowMajor>( | ||
| 479 | + 1, embed_); | ||
| 480 | + auto gmVSTensorTla = tla::MakeTensor(valueScale[vsOffset], | ||
| 481 | + gmVSLayoutTla, Arch::PositionGM{}); | ||
| 482 | + if (pvStaticNLoopNum == 1) { | ||
| 483 | + blockMmadPV.template operator()<quant_mode, 1, 1>( | ||
| 484 | + gmVTensorTla, ubOTmpTensorTla, gmVSTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 485 | + actualBlockShapePV, | ||
| 486 | + gatheredKvSTileIdxDe, kvSeqlen, | ||
| 487 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 488 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 489 | + smToMm2Flag, mm2ToReFlag); | ||
| 490 | + } else if (pvStaticNLoopNum == 2) { | ||
| 491 | + blockMmadPV.template operator()<quant_mode, 1, 2>( | ||
| 492 | + gmVTensorTla, ubOTmpTensorTla, gmVSTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 493 | + actualBlockShapePV, | ||
| 494 | + gatheredKvSTileIdxDe, kvSeqlen, | ||
| 495 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 496 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 497 | + smToMm2Flag, mm2ToReFlag); | ||
| 498 | + } else { | ||
| 499 | + blockMmadPV.template operator()<quant_mode, -1, -1>( | ||
| 500 | + gmVTensorTla, ubOTmpTensorTla, gmVSTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 501 | + actualBlockShapePV, | ||
| 502 | + gatheredKvSTileIdxDe, kvSeqlen, | ||
| 503 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 504 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 505 | + smToMm2Flag, mm2ToReFlag); | ||
| 506 | + } | ||
| 507 | + | ||
| 508 | + | ||
| 509 | + // rescale O | ||
| 510 | + Arch::CrossCoreFlag mm2ToReFlag(Mm2ToReFlagId); | ||
| 511 | + uint32_t curTileMod = gatheredKvSTileIdxDe % (PRE_LAUNCH + 1); | ||
| 512 | + epilogueRescaleO( | ||
| 513 | + gO[gmOffsetO], (GemmCoord){rowNum, embed_, kvSTileSizeAct}, | ||
| 514 | + curTileMod, gatheredKvSTileIdxDe, | ||
| 515 | + (gatheredKvSTileIdxDe == 0), | ||
| 516 | + (gatheredKvSTileIdxDe == kvSLoopNum - 1), | ||
| 517 | + mm2ToReFlag); | ||
| 518 | + | ||
| 519 | + } | ||
| 520 | + } | ||
| 521 | + } | ||
| 522 | + // release reverse sync flags | ||
| 523 | + ReleaseSyncFlags<4, 4, 4>(); | ||
| 524 | + } | ||
| 525 | + | ||
| 526 | + __aicore__ inline | ||
| 527 | + void FetchBaseShapeInfo(__gm__ EagleQuantBlockSparseAttentionTilingData *bsaTilingData) | ||
| 528 | + { | ||
| 529 | + batch_ = bsaTilingData->batch; | ||
| 530 | + qHeads_ = bsaTilingData->numHeads; | ||
| 531 | + kvHeads_ = bsaTilingData->kvHeads; | ||
| 532 | + embed_ = bsaTilingData->embeddingSize; | ||
| 533 | + firstBatchTaskNum_ = bsaTilingData->firstBatchTaskNum; | ||
| 534 | + totalTaskNum_ = bsaTilingData->totalTaskNum; | ||
| 535 | + blockShapeX_ = bsaTilingData->blockShapeX; | ||
| 536 | + blockShapeY_ = bsaTilingData->blockShapeY; | ||
| 537 | + scaleValue_ = bsaTilingData->scaleValue; | ||
| 538 | + // mask2idx tile info | ||
| 539 | + xBlockNumAligned_ = bsaTilingData->BsaMask2IdxTileInfo.xBlockNumAligned; | ||
| 540 | + yBlockNumAligned_ = bsaTilingData->BsaMask2IdxTileInfo.yBlockNumAligned; | ||
| 541 | + avgRowPerSubCore_ = bsaTilingData->BsaMask2IdxTileInfo.avgRowPerSubCore; | ||
| 542 | + preActiveSubCoreNum_ = bsaTilingData->BsaMask2IdxTileInfo.preActiveSubCoreNum; | ||
| 543 | + // base tile info | ||
| 544 | + qBaseTile_ = bsaTilingData->BsaBaseTileInfo.qBaseTile; | ||
| 545 | + kvBaseTile_ = bsaTilingData->BsaBaseTileInfo.kvBaseTile; | ||
| 546 | + // whether actual seqlen is provided | ||
| 547 | + actSeqAval_ = (!bsaTilingData->useUniformQSeqlen) && (!bsaTilingData->useUniformKvSeqlen); | ||
| 548 | + sparseIdxSize_ = bsaTilingData->selectIdxSize; | ||
| 549 | + // aligned seqlen q & kv | ||
| 550 | + qSeqlenAligned_ = bsaTilingData->maxQSeqlen; | ||
| 551 | + kvSeqlenAligned_ = bsaTilingData->maxKvSeqlen; | ||
| 552 | + } | ||
| 553 | + | ||
| 554 | + __aicore__ inline | ||
| 555 | + void CalcOnChipBufTileInfo(__gm__ EagleQuantBlockSparseAttentionTilingData *bsaTilingData) | ||
| 556 | + { | ||
| 557 | + mm1L1TileM_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm1L1TileM; | ||
| 558 | + mm1L1TileN_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm1L1TileN; | ||
| 559 | + mm1L1TileKLeft_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm1L1TileKLeft; | ||
| 560 | + mm1L1TileKRight_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm1L1TileKRight; | ||
| 561 | + mm2L1TileM_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm2L1TileM; | ||
| 562 | + mm2L1TileN_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm2L1TileN; | ||
| 563 | + mm2L1TileKLeft_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm2L1TileKLeft; | ||
| 564 | + mm2L1TileKRight_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm2L1TileKRight; | ||
| 565 | + qL1BufNum_ = bsaTilingData->BsaMmPhaseL1TileInfo.qL1BufNum; | ||
| 566 | + kL1BufNum_ = bsaTilingData->BsaMmPhaseL1TileInfo.kL1BufNum; | ||
| 567 | + vL1BufNum_ = bsaTilingData->BsaMmPhaseL1TileInfo.vL1BufNum; | ||
| 568 | + pL1BufNum_ = bsaTilingData->BsaMmPhaseL1TileInfo.pL1BufNum; | ||
| 569 | + Gemm::Block::Mm1L1TileHelper mm1L1TileHelper(mm1L1TileM_, mm1L1TileN_, mm1L1TileKLeft_, mm1L1TileKRight_, | ||
| 570 | + qL1BufNum_, kL1BufNum_); | ||
| 571 | + mm1L1TileHelper_ = mm1L1TileHelper; | ||
| 572 | + Gemm::Block::Mm2L1TileHelper mm2L1TileHelper(mm2L1TileM_, mm2L1TileN_, mm2L1TileKLeft_, mm2L1TileKRight_, | ||
| 573 | + pL1BufNum_, vL1BufNum_); | ||
| 574 | + mm2L1TileHelper_ = mm2L1TileHelper; | ||
| 575 | + mm2L1AddrStart_ = mm1L1TileM_ * mm1L1TileKLeft_ * qL1BufNum_ * sizeof(ElementQ) + | ||
| 576 | + mm1L1TileKRight_ * mm1L1TileN_ * kL1BufNum_ * sizeof(ElementK); | ||
| 577 | + mm1L0ATotalStages_ = (qBaseTile_ / BlockMmadQK::L0_TILE_M) * (embed_ / BlockMmadQK::L0_TILE_K); | ||
| 578 | + mm1L0BTotalStages_ = (kvBaseTile_ / BlockMmadQK::L0_TILE_N) * (embed_ / BlockMmadQK::L0_TILE_K); | ||
| 579 | + mm2L0ATotalStages_ = (qBaseTile_ / BlockMmadPV::L0_TILE_M) * (kvBaseTile_ / BlockMmadPV::L0_TILE_K); | ||
| 580 | + mm2L0BTotalStages_ = (kvBaseTile_ / BlockMmadPV::L0_TILE_K) * (embed_ / BlockMmadPV::L0_TILE_N); | ||
| 581 | + } | ||
| 582 | + | ||
| 583 | + __aicore__ inline | ||
| 584 | + uint64_t CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 585 | + uint32_t gatheredKvSTileIdx, uint32_t singleMm1L0Stages, | ||
| 586 | + uint32_t singleMm2L0Stages, uint32_t kvSLoopNum, | ||
| 587 | + bool isCurPhaseMm1) | ||
| 588 | + { | ||
| 589 | + uint64_t prefixSumStages; | ||
| 590 | + if (isCurPhaseMm1) { | ||
| 591 | + prefixSumStages = (gatheredKvSTileIdx <= PRE_LAUNCH) ? | ||
| 592 | + gatheredKvSTileIdx * singleMm1L0Stages : | ||
| 593 | + gatheredKvSTileIdx * singleMm1L0Stages + (gatheredKvSTileIdx - PRE_LAUNCH) * singleMm2L0Stages; | ||
| 594 | + } else { | ||
| 595 | + prefixSumStages = (gatheredKvSTileIdx < kvSLoopNum - PRE_LAUNCH) ? | ||
| 596 | + (gatheredKvSTileIdx + 1 + PRE_LAUNCH) * singleMm1L0Stages + gatheredKvSTileIdx * singleMm2L0Stages: | ||
| 597 | + kvSLoopNum * singleMm1L0Stages + gatheredKvSTileIdx * singleMm2L0Stages; | ||
| 598 | + } | ||
| 599 | + return prefixSumStages; | ||
| 600 | + } | ||
| 601 | + | ||
| 602 | + __aicore__ inline | ||
| 603 | + void InitCrossCoreDstBuf( | ||
| 604 | + AscendC::LocalTensor<ElementP> (&l1PTensor)[MAX_CROSS_CORE_BUF_STAGES], | ||
| 605 | + AscendC::LocalTensor<ElementS> (&ubSTensor)[UB_S_OTMP_BUF_STAGES], | ||
| 606 | + AscendC::LocalTensor<ElementOTmp> (&ubOTmpTensor)[UB_S_OTMP_BUF_STAGES]) | ||
| 607 | + { | ||
| 608 | + for (uint32_t i = 0; i < pL1BufNum_; i++) { | ||
| 609 | + l1PTensor[i] = resource.l1Buf.template GetBufferByByte<ElementP>( | ||
| 610 | + mm2L1AddrStart_ + mm2L1TileM_ * mm2L1TileKLeft_ * sizeof(ElementP) * i); | ||
| 611 | + } | ||
| 612 | + uint32_t rowNumPerSubCore = EpilogueOnlineSoftmax::SM_ROW_MAX_ELEM_NUM; | ||
| 613 | + uint32_t colNumPerSubCore = EpilogueOnlineSoftmax::SM_COL_MAX_ELEM_NUM; | ||
| 614 | + uint32_t rescaleCol = EpilogueRescaleO::RESCALE_COL_MAX_ELEM_NUM; | ||
| 615 | + for (uint32_t i = 0; i < UB_S_OTMP_BUF_STAGES; i++) { | ||
| 616 | + ubSTensor[i] = resource.ubBuf.template GetBufferByByte<ElementS>( | ||
| 617 | + rowNumPerSubCore * colNumPerSubCore * sizeof(ElementS) * i); | ||
| 618 | + ubOTmpTensor[i] = resource.ubBuf.template GetBufferByByte<ElementOTmp>( | ||
| 619 | + rowNumPerSubCore * colNumPerSubCore * sizeof(ElementS) * UB_S_OTMP_BUF_STAGES + | ||
| 620 | + rowNumPerSubCore * rescaleCol * sizeof(ElementOTmp) * i); | ||
| 621 | + } | ||
| 622 | + } | ||
| 623 | + | ||
| 624 | + template <uint32_t MM1_SM_MODE, uint32_t MM2_RE_MODE, uint32_t SM_MM2_MODE> | ||
| 625 | + __aicore__ inline | ||
| 626 | + void InitSyncFlags() | ||
| 627 | + { | ||
| 628 | + | ||
| 629 | + // same core sync between pipes | ||
| 630 | + // Query | ||
| 631 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 632 | + // Key | ||
| 633 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID1); | ||
| 634 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID2); | ||
| 635 | + // Value | ||
| 636 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID3); | ||
| 637 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID4); | ||
| 638 | + // L0A | ||
| 639 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID0); | ||
| 640 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID1); | ||
| 641 | + // L0B | ||
| 642 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID2); | ||
| 643 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID3); | ||
| 644 | + // L0C | ||
| 645 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID0); | ||
| 646 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID1); | ||
| 647 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID2); | ||
| 648 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID3); | ||
| 649 | + // VSDB (L1 Value Scale Double Buffer) | ||
| 650 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_FIX>(EVENT_ID0); | ||
| 651 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_FIX>(EVENT_ID1); | ||
| 652 | + AscendC::SetFlag<AscendC::HardEvent::FIX_MTE2>(EVENT_ID0); | ||
| 653 | + // cross core sync | ||
| 654 | + if constexpr (SM_MM2_MODE == 4U) { | ||
| 655 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(2); | ||
| 656 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(18); | ||
| 657 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(3); | ||
| 658 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(19); | ||
| 659 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(4); | ||
| 660 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(20); | ||
| 661 | + } | ||
| 662 | + | ||
| 663 | + | ||
| 664 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 665 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID1); | ||
| 666 | + // mask2index | ||
| 667 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID0); | ||
| 668 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID1); | ||
| 669 | + // softmax | ||
| 670 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID2); | ||
| 671 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID3); | ||
| 672 | + // rescale | ||
| 673 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 674 | + | ||
| 675 | + AscendC::SetFlag<AscendC::HardEvent::S_MTE3>(EVENT_ID0); | ||
| 676 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(EVENT_ID0); | ||
| 677 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(EVENT_ID1); | ||
| 678 | + if constexpr (MM1_SM_MODE == 4U) { | ||
| 679 | + AscendC::CrossCoreSetFlag<MM1_SM_MODE, PIPE_V>(0); | ||
| 680 | + AscendC::CrossCoreSetFlag<MM1_SM_MODE, PIPE_V>(1); | ||
| 681 | + } | ||
| 682 | + if constexpr (MM2_RE_MODE == 4U) { | ||
| 683 | + AscendC::CrossCoreSetFlag<MM2_RE_MODE, PIPE_V>(5); | ||
| 684 | + AscendC::CrossCoreSetFlag<MM2_RE_MODE, PIPE_V>(6); | ||
| 685 | + } | ||
| 686 | + | ||
| 687 | + } | ||
| 688 | + | ||
| 689 | + template <uint32_t MM1_SM_MODE, uint32_t MM2_RE_MODE, uint32_t SM_MM2_MODE> | ||
| 690 | + __aicore__ inline | ||
| 691 | + void ReleaseSyncFlags() | ||
| 692 | + { | ||
| 693 | + | ||
| 694 | + // same core sync between pipes | ||
| 695 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 696 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID1); | ||
| 697 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID2); | ||
| 698 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID3); | ||
| 699 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID4); | ||
| 700 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID0); | ||
| 701 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID1); | ||
| 702 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID2); | ||
| 703 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID3); | ||
| 704 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID0); | ||
| 705 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID1); | ||
| 706 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID2); | ||
| 707 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID3); | ||
| 708 | + // VSDB (L1 Value Scale Double Buffer) | ||
| 709 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_FIX>(EVENT_ID0); | ||
| 710 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_FIX>(EVENT_ID1); | ||
| 711 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_MTE2>(EVENT_ID0); | ||
| 712 | + if constexpr (MM1_SM_MODE == 4U) { | ||
| 713 | + AscendC::CrossCoreWaitFlag<MM1_SM_MODE, PIPE_FIX>(0); | ||
| 714 | + AscendC::CrossCoreWaitFlag<MM1_SM_MODE, PIPE_FIX>(1); | ||
| 715 | + AscendC::CrossCoreWaitFlag<MM1_SM_MODE, PIPE_FIX>(16); | ||
| 716 | + AscendC::CrossCoreWaitFlag<MM1_SM_MODE, PIPE_FIX>(17); | ||
| 717 | + } | ||
| 718 | + if constexpr (MM2_RE_MODE == 4U) { | ||
| 719 | + AscendC::CrossCoreWaitFlag<MM2_RE_MODE, PIPE_FIX>(5); | ||
| 720 | + AscendC::CrossCoreWaitFlag<MM2_RE_MODE, PIPE_FIX>(21); | ||
| 721 | + AscendC::CrossCoreWaitFlag<MM2_RE_MODE, PIPE_FIX>(6); | ||
| 722 | + AscendC::CrossCoreWaitFlag<MM2_RE_MODE, PIPE_FIX>(22); | ||
| 723 | + } | ||
| 724 | + | ||
| 725 | + | ||
| 726 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 727 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID1); | ||
| 728 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID0); | ||
| 729 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID1); | ||
| 730 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID2); | ||
| 731 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID3); | ||
| 732 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 733 | + AscendC::WaitFlag<AscendC::HardEvent::S_MTE3>(EVENT_ID0); | ||
| 734 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(EVENT_ID0); | ||
| 735 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(EVENT_ID1); | ||
| 736 | + if constexpr (SM_MM2_MODE == 4U) { | ||
| 737 | + AscendC::CrossCoreWaitFlag<SM_MM2_MODE, PIPE_MTE3>(2); | ||
| 738 | + AscendC::CrossCoreWaitFlag<SM_MM2_MODE, PIPE_MTE3>(3); | ||
| 739 | + AscendC::CrossCoreWaitFlag<SM_MM2_MODE, PIPE_MTE3>(4); | ||
| 740 | + } | ||
| 741 | + | ||
| 742 | + AscendC::PipeBarrier<PIPE_ALL>(); | ||
| 743 | + } | ||
| 744 | + | ||
| 745 | +private: | ||
| 746 | + Arch::Resource<ArchTag> resource; | ||
| 747 | + /* | ||
| 748 | + tiling info, which are const in each kernel launch | ||
| 749 | + */ | ||
| 750 | + // basic shape info | ||
| 751 | + uint32_t batch_; | ||
| 752 | + uint32_t qHeads_; | ||
| 753 | + uint32_t kvHeads_; | ||
| 754 | + uint32_t embed_; | ||
| 755 | + uint32_t firstBatchTaskNum_; | ||
| 756 | + uint32_t totalTaskNum_; | ||
| 757 | + uint32_t blockShapeX_; | ||
| 758 | + uint32_t blockShapeY_; | ||
| 759 | + float scaleValue_; | ||
| 760 | + // mask2idx tile info | ||
| 761 | + uint32_t xBlockNumAligned_; | ||
| 762 | + uint32_t yBlockNumAligned_; | ||
| 763 | + uint32_t avgRowPerSubCore_; | ||
| 764 | + uint32_t preActiveSubCoreNum_; | ||
| 765 | + // base tile info | ||
| 766 | + uint32_t qBaseTile_; | ||
| 767 | + uint32_t kvBaseTile_; | ||
| 768 | + // whether actual seqlen is provided | ||
| 769 | + uint32_t actSeqAval_; | ||
| 770 | + // workspace size | ||
| 771 | + uint64_t sparseIdxSize_; | ||
| 772 | + // aligned seqlen q & kv | ||
| 773 | + int64_t qSeqlenAligned_; | ||
| 774 | + int64_t kvSeqlenAligned_; | ||
| 775 | + // L1 tile info | ||
| 776 | + uint32_t mm1L1TileM_; | ||
| 777 | + uint32_t mm1L1TileN_; | ||
| 778 | + uint32_t mm1L1TileKLeft_; | ||
| 779 | + uint32_t mm1L1TileKRight_; | ||
| 780 | + uint32_t mm2L1TileM_; | ||
| 781 | + uint32_t mm2L1TileN_; | ||
| 782 | + uint32_t mm2L1TileKLeft_; | ||
| 783 | + uint32_t mm2L1TileKRight_; | ||
| 784 | + uint32_t qL1BufNum_; | ||
| 785 | + uint32_t kL1BufNum_; | ||
| 786 | + uint32_t vL1BufNum_; | ||
| 787 | + uint32_t pL1BufNum_; | ||
| 788 | + uint32_t mm1L0ATotalStages_; | ||
| 789 | + uint32_t mm1L0BTotalStages_; | ||
| 790 | + uint32_t mm2L0ATotalStages_; | ||
| 791 | + uint32_t mm2L0BTotalStages_; | ||
| 792 | + uint32_t mm2L1AddrStart_ = 0; | ||
| 793 | + Gemm::Block::Mm1L1TileHelper mm1L1TileHelper_; | ||
| 794 | + Gemm::Block::Mm2L1TileHelper mm2L1TileHelper_; | ||
| 795 | +}; | ||
| 796 | + | ||
| 797 | +} | ||
| 798 | + | ||
| 799 | + | ||
| @@ -0,0 +1,722 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +using namespace NpuArch; | ||
| 18 | +using namespace tla; | ||
| 19 | + | ||
| 20 | +namespace BsaKernelArch35 { | ||
| 21 | + | ||
| 22 | +template < | ||
| 23 | + class EpilogueMask2Idx, | ||
| 24 | + class BlockMmadQK, | ||
| 25 | + class EpilogueOnlineSoftmax, | ||
| 26 | + class BlockMmadPV, | ||
| 27 | + class EpilogueRescaleO, | ||
| 28 | + Format qFormat, | ||
| 29 | + Format kvFormat> | ||
| 30 | +class BsaRegularKernelArch35 { | ||
| 31 | +public: | ||
| 32 | + using ArchTag = typename BlockMmadPV::ArchTag; | ||
| 33 | + | ||
| 34 | + using ElementQ = typename BlockMmadQK::ElementA; | ||
| 35 | + using ElementK = typename BlockMmadQK::ElementB; | ||
| 36 | + using ElementS = typename EpilogueOnlineSoftmax::ElementInput; | ||
| 37 | + using ElementP = typename BlockMmadPV::ElementA; | ||
| 38 | + using ElementV = typename BlockMmadPV::ElementB; | ||
| 39 | + using ElementOTmp = typename BlockMmadPV::ElementC; | ||
| 40 | + using ElementO = typename EpilogueRescaleO::ElementO; | ||
| 41 | + using ElementSparseMask = typename EpilogueMask2Idx::ElementSparseMask; | ||
| 42 | + using ElementSparseIdx = typename EpilogueMask2Idx::ElementSparseIdx; | ||
| 43 | + using ElementSparseCount = typename EpilogueMask2Idx::ElementSparseCount; | ||
| 44 | + | ||
| 45 | + using LayoutQ = layout::RowMajor; | ||
| 46 | + using LayoutK = layout::ColumnMajor; | ||
| 47 | + using LayoutS = layout::RowMajor; | ||
| 48 | + using LayoutP = layout::RowMajor; | ||
| 49 | + using LayoutV = layout::RowMajor; | ||
| 50 | + using LayoutO = layout::RowMajor; | ||
| 51 | + using LayoutOTmp = layout::RowMajor; | ||
| 52 | + using LayoutSparseIdx = layout::RowMajor; | ||
| 53 | + using LayoutSparseCount = layout::RowMajor; | ||
| 54 | + | ||
| 55 | + using LayoutTagL1P = typename BlockMmadPV::LayoutTagL1A; | ||
| 56 | + | ||
| 57 | + static constexpr uint32_t PRE_LAUNCH = 2; | ||
| 58 | + static constexpr uint32_t MAX_CROSS_CORE_BUF_STAGES = PRE_LAUNCH + 1; | ||
| 59 | + static constexpr uint32_t UB_S_OTMP_BUF_STAGES = 2; | ||
| 60 | + // Methods | ||
| 61 | + __aicore__ inline | ||
| 62 | + BsaRegularKernelArch35() {} | ||
| 63 | + | ||
| 64 | + __aicore__ inline | ||
| 65 | + int GetQkStaticLoopNum() | ||
| 66 | + { | ||
| 67 | + return ((qBaseTile_ == BlockMmadQK::L0_TILE_M) && | ||
| 68 | + (embed_ == BlockMmadQK::L0_TILE_K) && | ||
| 69 | + ((kvBaseTile_ == BlockMmadQK::L0_TILE_N) || | ||
| 70 | + (kvBaseTile_ == BlockMmadQK::L0_TILE_N * 2U))) ? | ||
| 71 | + 1 : Gemm::Block::Arch35MmadOpt::DYNAMIC_LOOP; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + __aicore__ inline | ||
| 75 | + int GetPvStaticNLoopNum() | ||
| 76 | + { | ||
| 77 | + if (qBaseTile_ != BlockMmadPV::L0_TILE_M) { | ||
| 78 | + return Gemm::Block::Arch35MmadOpt::DYNAMIC_LOOP; | ||
| 79 | + } | ||
| 80 | + if (embed_ == BlockMmadPV::L0_TILE_N) { | ||
| 81 | + return 1; | ||
| 82 | + } | ||
| 83 | + if (embed_ == BlockMmadPV::L0_TILE_N * 2U) { | ||
| 84 | + return 2; | ||
| 85 | + } | ||
| 86 | + return Gemm::Block::Arch35MmadOpt::DYNAMIC_LOOP; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + template<int quant_mode=0> | ||
| 90 | + __aicore__ inline | ||
| 91 | + void operator()(BsaKernelParamsArch35 const ¶ms) | ||
| 92 | + { | ||
| 93 | + static_assert(quant_mode == 0); | ||
| 94 | + __gm__ EagleQuantBlockSparseAttentionTilingData *bsaTilingData = | ||
| 95 | + reinterpret_cast<__gm__ EagleQuantBlockSparseAttentionTilingData *>(params.tiling); | ||
| 96 | + FetchBaseShapeInfo(bsaTilingData); | ||
| 97 | + CalcOnChipBufTileInfo(bsaTilingData); | ||
| 98 | + // global buffers | ||
| 99 | + AscendC::GlobalTensor<ElementQ> gQ; | ||
| 100 | + gQ.SetGlobalBuffer((__gm__ ElementQ *)params.q); | ||
| 101 | + AscendC::GlobalTensor<ElementK> gK; | ||
| 102 | + gK.SetGlobalBuffer((__gm__ ElementK *)params.k); | ||
| 103 | + AscendC::GlobalTensor<ElementV> gV; | ||
| 104 | + gV.SetGlobalBuffer((__gm__ ElementV *)params.v); | ||
| 105 | + AscendC::GlobalTensor<int64_t> gActualQseqlen; | ||
| 106 | + gActualQseqlen.SetGlobalBuffer((__gm__ int64_t *)params.actualQseqlen); | ||
| 107 | + AscendC::GlobalTensor<int64_t> gActualKvseqlen; | ||
| 108 | + gActualKvseqlen.SetGlobalBuffer((__gm__ int64_t *)params.actualKvseqlen); | ||
| 109 | + AscendC::GlobalTensor<uint8_t> gBlockSparseMask; | ||
| 110 | + gBlockSparseMask.SetGlobalBuffer((__gm__ uint8_t *)params.blockSparseMask); | ||
| 111 | + AscendC::GlobalTensor<ElementO> gO; | ||
| 112 | + gO.SetGlobalBuffer((__gm__ ElementO *)params.o); | ||
| 113 | + AscendC::GlobalTensor<ElementSparseIdx> gSparseIdx; | ||
| 114 | + if (bsaTilingData->sparsePatternMode == SPARSE_PATTERN_MODE_TABLE) { | ||
| 115 | + gSparseIdx.SetGlobalBuffer((__gm__ ElementSparseIdx *)params.blockSparseMask); | ||
| 116 | + } else { | ||
| 117 | + gSparseIdx.SetGlobalBuffer((__gm__ ElementSparseIdx *)params.workSpace); | ||
| 118 | + } | ||
| 119 | + AscendC::GlobalTensor<ElementSparseCount> gSparseCount; | ||
| 120 | + gSparseCount.SetGlobalBuffer((__gm__ ElementSparseCount *)(params.workSpace + sparseIdxSize_)); | ||
| 121 | + | ||
| 122 | + // cross core data move dst buffers | ||
| 123 | + AscendC::LocalTensor<ElementP> l1PTensor[MAX_CROSS_CORE_BUF_STAGES]; | ||
| 124 | + AscendC::LocalTensor<ElementS> ubSTensor[UB_S_OTMP_BUF_STAGES]; | ||
| 125 | + AscendC::LocalTensor<ElementOTmp> ubOTmpTensor[UB_S_OTMP_BUF_STAGES]; | ||
| 126 | + InitCrossCoreDstBuf(l1PTensor, ubSTensor, ubOTmpTensor); | ||
| 127 | + // core idx | ||
| 128 | + uint32_t coreIdx = AscendC::GetBlockIdx(); | ||
| 129 | + uint32_t coreNum = AscendC::GetBlockNum(); | ||
| 130 | + // set reverse sync flags | ||
| 131 | + InitSyncFlags<4, 4, 4>(); | ||
| 132 | + | ||
| 133 | + uint32_t totalRowNumBlockMask = batch_ * qHeads_ * xBlockNumAligned_; | ||
| 134 | + if (bsaTilingData->sparsePatternMode == SPARSE_PATTERN_MODE_TABLE) { | ||
| 135 | + SparseTable2Count(resource, gSparseIdx, gSparseCount, | ||
| 136 | + totalRowNumBlockMask, yBlockNumAligned_, avgRowPerSubCore_, preActiveSubCoreNum_); | ||
| 137 | + } else { | ||
| 138 | + EpilogueMask2Idx epilogueMask2Idx(resource); | ||
| 139 | + epilogueMask2Idx( | ||
| 140 | + gBlockSparseMask, gSparseIdx, gSparseCount, | ||
| 141 | + totalRowNumBlockMask, yBlockNumAligned_, avgRowPerSubCore_, preActiveSubCoreNum_); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + AscendC::SyncAll<false>(); | ||
| 145 | + | ||
| 146 | + coreIdx = AscendC::GetBlockIdx(); | ||
| 147 | + BlockMmadQK blockMmadQK(resource, mm1L1TileHelper_); | ||
| 148 | + BlockMmadPV blockMmadPV(resource, mm2L1AddrStart_, mm2L1TileHelper_); | ||
| 149 | + | ||
| 150 | + | ||
| 151 | + coreIdx = AscendC::GetBlockIdx() / AscendC::GetSubBlockNum(); | ||
| 152 | + EpilogueOnlineSoftmax epilogueOnlineSoftmax(resource, scaleValue_); | ||
| 153 | + EpilogueRescaleO epilogueRescaleO(resource); | ||
| 154 | + | ||
| 155 | + uint32_t qSTileNumPerFullXBlock = CeilDiv(blockShapeX_, qBaseTile_); | ||
| 156 | + // Calculate strides based on layout | ||
| 157 | + // For TND: [T, N, D], stride = N * D | ||
| 158 | + // For BNSD: [B, N, S, D], strideB = N * S * D, strideN = S * D, strideS = D | ||
| 159 | + int64_t strideQO = 0; | ||
| 160 | + int64_t strideKV = 0; | ||
| 161 | + int64_t strideQOB = 0; // BNSD batch_ stride for Q | ||
| 162 | + int64_t strideQON = 0; // BNSD head stride for Q | ||
| 163 | + int64_t strideQOS = 0; // BNSD seq stride for Q | ||
| 164 | + int64_t strideKVB = 0; // BNSD batch_ stride for KV | ||
| 165 | + int64_t strideKVN = 0; // BNSD head stride for KV | ||
| 166 | + int64_t strideKVS = 0; // BNSD seq stride for KV | ||
| 167 | + if constexpr (qFormat == Format::BNSD) { | ||
| 168 | + strideQOB = qHeads_ * qSeqlenAligned_ * embed_; // batch_ stride | ||
| 169 | + strideQON = qSeqlenAligned_ * embed_; // head stride | ||
| 170 | + strideQOS = embed_; // seq stride | ||
| 171 | + } else if constexpr (qFormat == Format::TND) { | ||
| 172 | + strideQO = qHeads_ * embed_; | ||
| 173 | + } | ||
| 174 | + if constexpr (kvFormat == Format::BNSD) { | ||
| 175 | + strideKVB = kvHeads_ * kvSeqlenAligned_ * embed_; // batch_ stride | ||
| 176 | + strideKVN = kvSeqlenAligned_ * embed_; // head stride | ||
| 177 | + strideKVS = embed_; // seq stride | ||
| 178 | + } else if constexpr (kvFormat == Format::TND) { | ||
| 179 | + strideKV = kvHeads_ * embed_; | ||
| 180 | + } | ||
| 181 | + uint32_t embedRound = RoundUp(embed_, 16); | ||
| 182 | + uint32_t groupSize = qHeads_ / kvHeads_; | ||
| 183 | + int qkStaticLoopNum = GetQkStaticLoopNum(); | ||
| 184 | + int pvStaticNLoopNum = GetPvStaticNLoopNum(); | ||
| 185 | + int64_t qBOffset = 0; | ||
| 186 | + int64_t kBOffset = 0; | ||
| 187 | + int64_t vBOffset = 0; | ||
| 188 | + int64_t oBOffset = 0; | ||
| 189 | + uint32_t preTotalTaskNum = 0; | ||
| 190 | + uint32_t curBatch = 0; | ||
| 191 | + int64_t qSeqlen = actSeqAval_ ? gActualQseqlen.GetValue(curBatch) : qSeqlenAligned_; | ||
| 192 | + int64_t kvSeqlen = actSeqAval_ ? gActualKvseqlen.GetValue(curBatch) : kvSeqlenAligned_; | ||
| 193 | + uint32_t curQSTileNum = GetCurQSTileNum(qSeqlen, blockShapeX_, qBaseTile_); | ||
| 194 | + uint32_t curTotalTaskNum = firstBatchTaskNum_; | ||
| 195 | + // Go through each task | ||
| 196 | + for (uint32_t taskIdx = coreIdx; taskIdx < totalTaskNum_; taskIdx += coreNum) { | ||
| 197 | + while (taskIdx >= curTotalTaskNum) { | ||
| 198 | + ++curBatch; | ||
| 199 | + preTotalTaskNum = curTotalTaskNum; | ||
| 200 | + if constexpr (qFormat == Format::TND) { | ||
| 201 | + qBOffset += qSeqlen * strideQO; | ||
| 202 | + oBOffset += qSeqlen * strideQO; | ||
| 203 | + } | ||
| 204 | + if constexpr (kvFormat == Format::TND) { | ||
| 205 | + kBOffset += kvSeqlen * strideKV; | ||
| 206 | + vBOffset += kvSeqlen * strideKV; | ||
| 207 | + } | ||
| 208 | + qSeqlen = actSeqAval_ ? gActualQseqlen.GetValue(curBatch) : qSeqlenAligned_; | ||
| 209 | + kvSeqlen = actSeqAval_ ? gActualKvseqlen.GetValue(curBatch) : kvSeqlenAligned_; | ||
| 210 | + curQSTileNum = GetCurQSTileNum(qSeqlen, blockShapeX_, qBaseTile_); | ||
| 211 | + curTotalTaskNum += curQSTileNum * qHeads_; | ||
| 212 | + } | ||
| 213 | + uint32_t taskIdxCurBatch = taskIdx - preTotalTaskNum; | ||
| 214 | + uint32_t qHeadIdx = taskIdxCurBatch / curQSTileNum; | ||
| 215 | + uint32_t kvHeadIdx = qHeadIdx / groupSize; | ||
| 216 | + uint32_t qSTileIdx = taskIdxCurBatch - qHeadIdx * curQSTileNum; | ||
| 217 | + // corresponding xBlock index of cur task | ||
| 218 | + uint32_t xBlockIdx = qSTileIdx / qSTileNumPerFullXBlock; | ||
| 219 | + // the q base tile index within the corrsponding xBlock of cur task | ||
| 220 | + uint32_t qSTileIdxCurXBlock = qSTileIdx - xBlockIdx * qSTileNumPerFullXBlock; | ||
| 221 | + // corresponding head index of cur task | ||
| 222 | + // corresponding blockSparseMask gm offset of cur task | ||
| 223 | + // gmBlockSparseMask has the shape [B, qN, xBlockNumAligned, yBlockNumAligned] | ||
| 224 | + int64_t sparseMaskBOffset = curBatch * qHeads_ * xBlockNumAligned_ * yBlockNumAligned_; | ||
| 225 | + int64_t sparseMaskNOffset = qHeadIdx * xBlockNumAligned_ * yBlockNumAligned_; | ||
| 226 | + int64_t sparseMaskXOffset = xBlockIdx * yBlockNumAligned_; | ||
| 227 | + int64_t gmOffsetSparseMask = sparseMaskBOffset + sparseMaskNOffset + sparseMaskXOffset; | ||
| 228 | + // corresponding Q/K/V/O gm offset of cur task | ||
| 229 | + int64_t gmOffsetQ = 0; | ||
| 230 | + int64_t gmOffsetK = 0; | ||
| 231 | + int64_t gmOffsetV = 0; | ||
| 232 | + int64_t gmOffsetO = 0; | ||
| 233 | + int64_t qSOffset = xBlockIdx * blockShapeX_ + qSTileIdxCurXBlock * qBaseTile_; | ||
| 234 | + if constexpr (qFormat == Format::BNSD) { | ||
| 235 | + qBOffset = curBatch * strideQOB; | ||
| 236 | + oBOffset = curBatch * strideQOB; | ||
| 237 | + gmOffsetQ = qBOffset + qHeadIdx * strideQON + qSOffset * strideQOS; | ||
| 238 | + gmOffsetO = oBOffset + qHeadIdx * strideQON + qSOffset * strideQOS; | ||
| 239 | + } else if constexpr (qFormat == Format::TND) { | ||
| 240 | + gmOffsetQ = qBOffset + qSOffset * strideQO + qHeadIdx * embed_; | ||
| 241 | + gmOffsetO = oBOffset + qSOffset * strideQO + qHeadIdx * embed_; | ||
| 242 | + } | ||
| 243 | + if constexpr (kvFormat == Format::BNSD) { | ||
| 244 | + kBOffset = curBatch * strideKVB; | ||
| 245 | + vBOffset = curBatch * strideKVB; | ||
| 246 | + gmOffsetK = kBOffset + kvHeadIdx * strideKVN; | ||
| 247 | + gmOffsetV = vBOffset + kvHeadIdx * strideKVN; | ||
| 248 | + } else if constexpr (kvFormat == Format::TND) { | ||
| 249 | + gmOffsetK = kBOffset + kvHeadIdx * embed_; | ||
| 250 | + gmOffsetV = vBOffset + kvHeadIdx * embed_; | ||
| 251 | + } | ||
| 252 | + // the actual x block num of cur batch_, calc by actual qseqlen | ||
| 253 | + uint32_t xBlockNumAval = static_cast<uint32_t>(CeilDiv(qSeqlen, static_cast<int64_t>(blockShapeX_))); | ||
| 254 | + uint32_t xBlockSize = (xBlockIdx == xBlockNumAval - 1) ? | ||
| 255 | + (qSeqlen - xBlockIdx * blockShapeX_) : blockShapeX_; | ||
| 256 | + uint32_t qSTileNumCurXBlock = CeilDiv(xBlockSize, qBaseTile_); | ||
| 257 | + uint32_t qSTileSizeAct = (qSTileIdxCurXBlock == qSTileNumCurXBlock - 1) ? | ||
| 258 | + (xBlockSize - qSTileIdxCurXBlock * qBaseTile_) : qBaseTile_; | ||
| 259 | + // calc the gathered kvS from sparse mask | ||
| 260 | + uint32_t gmOffsetSparseCount = | ||
| 261 | + curBatch * qHeads_ * xBlockNumAligned_ + qHeadIdx * xBlockNumAligned_ + xBlockIdx; | ||
| 262 | + uint32_t yBlockNumRsvd = gSparseCount.GetValue(gmOffsetSparseCount); | ||
| 263 | + if (yBlockNumRsvd == 0) { | ||
| 264 | + continue; | ||
| 265 | + } | ||
| 266 | + uint32_t gmOffsetSparseIdx = gmOffsetSparseCount * yBlockNumAligned_; | ||
| 267 | + uint32_t lastIdxOffset = gmOffsetSparseIdx + yBlockNumRsvd - 1; | ||
| 268 | + uint32_t lastSparseIdx = gSparseIdx.GetValue(lastIdxOffset); | ||
| 269 | + | ||
| 270 | + uint32_t yBlockNumAval = static_cast<uint32_t>(CeilDiv(kvSeqlen, static_cast<int64_t>(blockShapeY_))); | ||
| 271 | + uint32_t lastYBlockSize = (lastSparseIdx == yBlockNumAval - 1) ? | ||
| 272 | + kvSeqlen - lastSparseIdx * blockShapeY_ : blockShapeY_; | ||
| 273 | + int64_t gatheredKvSeqlen = (yBlockNumRsvd - 1) * blockShapeY_ + lastYBlockSize; | ||
| 274 | + // the rowNum of cur task | ||
| 275 | + // no qS*qN combination even in GQA/MQA senario, since each qN has a different sparse pattern | ||
| 276 | + uint32_t rowNum = qSTileSizeAct; | ||
| 277 | + uint32_t rowNumRound = RoundUp(rowNum, 16); | ||
| 278 | + uint32_t kvSLoopNum = static_cast<uint32_t>(CeilDiv(gatheredKvSeqlen, static_cast<int64_t>(kvBaseTile_))); | ||
| 279 | + uint32_t kvSTileSizeAct = kvBaseTile_; | ||
| 280 | + | ||
| 281 | + uint32_t kvShapeCol = 0; | ||
| 282 | + uint32_t qShapeCol = 0; | ||
| 283 | + if constexpr (qFormat == Format::BNSD) { | ||
| 284 | + qShapeCol = strideQOS; | ||
| 285 | + } else if constexpr (qFormat == Format::TND) { | ||
| 286 | + qShapeCol = strideQO; | ||
| 287 | + } | ||
| 288 | + if constexpr (kvFormat == Format::BNSD) { | ||
| 289 | + kvShapeCol = strideKVS; | ||
| 290 | + } else if constexpr (kvFormat == Format::TND) { | ||
| 291 | + kvShapeCol = strideKV; | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + GemmCoord actualBlockShapeQ{rowNum, embed_, 0}; | ||
| 295 | + if constexpr (std::is_same_v<LayoutQ, layout::RowMajor>) { | ||
| 296 | + auto gmQLayoutTla = tla::MakeLayout<ElementQ, LayoutQ>(qBaseTile_, qShapeCol); | ||
| 297 | + auto gmQTensorTla = tla::MakeTensor(gQ[gmOffsetQ], gmQLayoutTla, Arch::PositionGM{}); | ||
| 298 | + blockMmadQK.loadQGM(gmQTensorTla, actualBlockShapeQ); | ||
| 299 | + } else { | ||
| 300 | + auto gmQLayoutTla = tla::MakeLayout<ElementQ, LayoutQ>(qShapeCol, qBaseTile_); | ||
| 301 | + auto gmQTensorTla = tla::MakeTensor(gQ[gmOffsetQ], gmQLayoutTla, Arch::PositionGM{}); | ||
| 302 | + blockMmadQK.loadQGM(gmQTensorTla, actualBlockShapeQ); | ||
| 303 | + } | ||
| 304 | + | ||
| 305 | + auto gmKLayoutTla = tla::MakeLayout<ElementK, LayoutK>(kvShapeCol, kvBaseTile_); | ||
| 306 | + auto gmKTensorTla = tla::MakeTensor(gK[gmOffsetK], gmKLayoutTla, Arch::PositionGM{}); | ||
| 307 | + | ||
| 308 | + auto gmVLayoutTla = tla::MakeLayout<ElementV, LayoutV>(kvBaseTile_, kvShapeCol); | ||
| 309 | + auto gmVTensorTla = tla::MakeTensor(gV[gmOffsetV], gmVLayoutTla, Arch::PositionGM{}); | ||
| 310 | + | ||
| 311 | + | ||
| 312 | + uint32_t oShapeCol = 0; | ||
| 313 | + if constexpr (qFormat == Format::BNSD) { | ||
| 314 | + oShapeCol = strideQOS; | ||
| 315 | + } else if constexpr (qFormat == Format::TND) { | ||
| 316 | + oShapeCol = strideQO; | ||
| 317 | + } | ||
| 318 | + auto gmOLayoutTla = tla::MakeLayout<ElementO, LayoutO>(qBaseTile_, oShapeCol); | ||
| 319 | + auto gmOTensorTla = tla::MakeTensor(gO[gmOffsetO], gmOLayoutTla, Arch::PositionGM{}); | ||
| 320 | + | ||
| 321 | + for (uint32_t gatheredKvSTileIdx = 0; gatheredKvSTileIdx < kvSLoopNum + PRE_LAUNCH; gatheredKvSTileIdx++) { | ||
| 322 | + if (gatheredKvSTileIdx < kvSLoopNum) { | ||
| 323 | + if (gatheredKvSTileIdx == kvSLoopNum - 1) { | ||
| 324 | + kvSTileSizeAct = gatheredKvSeqlen - gatheredKvSTileIdx * kvBaseTile_; | ||
| 325 | + } else { | ||
| 326 | + kvSTileSizeAct = kvBaseTile_; | ||
| 327 | + } | ||
| 328 | + // QK | ||
| 329 | + GemmCoord actualBlockShapeQK{rowNum, kvSTileSizeAct, embed_}; | ||
| 330 | + uint32_t ubSBufId = gatheredKvSTileIdx % UB_S_OTMP_BUF_STAGES; | ||
| 331 | + auto ubSLayoutTla = tla::MakeLayout<ElementS, LayoutS>(rowNumRound, RoundUp(kvSTileSizeAct, 16)); | ||
| 332 | + auto ubSTensorTla = tla::MakeTensor(ubSTensor[ubSBufId], | ||
| 333 | + ubSLayoutTla, Arch::PositionUB{}); | ||
| 334 | + uint32_t Mm1ToSmFlagId = ubSBufId; | ||
| 335 | + Arch::CrossCoreFlag mm1ToSmFlag(Mm1ToSmFlagId); | ||
| 336 | + | ||
| 337 | + uint64_t prefixSumL0AStages = CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 338 | + gatheredKvSTileIdx, mm1L0ATotalStages_, mm2L0ATotalStages_, kvSLoopNum, true); | ||
| 339 | + uint64_t prefixSumL0BStages = CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 340 | + gatheredKvSTileIdx, mm1L0BTotalStages_, mm2L0BTotalStages_, kvSLoopNum, true); | ||
| 341 | + if (qkStaticLoopNum == 1) { | ||
| 342 | + blockMmadQK.template operator()<0, 1, 1>( | ||
| 343 | + gmKTensorTla, ubSTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 344 | + actualBlockShapeQK, | ||
| 345 | + gatheredKvSTileIdx, kvSeqlen, | ||
| 346 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 347 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 348 | + mm1ToSmFlag, 1.0f); | ||
| 349 | + } else { | ||
| 350 | + blockMmadQK.template operator()<0, -1, -1>( | ||
| 351 | + gmKTensorTla, ubSTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 352 | + actualBlockShapeQK, | ||
| 353 | + gatheredKvSTileIdx, kvSeqlen, | ||
| 354 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 355 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 356 | + mm1ToSmFlag, 1.0f); | ||
| 357 | + } | ||
| 358 | + if (gatheredKvSTileIdx == kvSLoopNum - 1) | ||
| 359 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 360 | + | ||
| 361 | + // SM | ||
| 362 | + uint32_t l1PBufId = gatheredKvSTileIdx % pL1BufNum_; | ||
| 363 | + uint32_t smToMm2FlagId = l1PBufId + UB_S_OTMP_BUF_STAGES; | ||
| 364 | + Arch::CrossCoreFlag smToMm2Flag(smToMm2FlagId); | ||
| 365 | + auto l1PLayoutTla = tla::MakeLayout<ElementP, NpuArch::layout::zN>(rowNum, kvSTileSizeAct); | ||
| 366 | + auto l1PTensorTla = tla::MakeTensor(l1PTensor[l1PBufId], | ||
| 367 | + l1PLayoutTla, Arch::PositionL1{}); | ||
| 368 | + | ||
| 369 | + epilogueOnlineSoftmax( | ||
| 370 | + l1PTensorTla, | ||
| 371 | + actualBlockShapeQK, | ||
| 372 | + (gatheredKvSTileIdx == 0), | ||
| 373 | + ubSBufId, | ||
| 374 | + l1PBufId, | ||
| 375 | + mm1ToSmFlag, | ||
| 376 | + smToMm2Flag); | ||
| 377 | + | ||
| 378 | + } | ||
| 379 | + if (gatheredKvSTileIdx >= PRE_LAUNCH) { | ||
| 380 | + uint32_t gatheredKvSTileIdxDe = gatheredKvSTileIdx - PRE_LAUNCH; | ||
| 381 | + if (gatheredKvSTileIdxDe == kvSLoopNum - 1) { | ||
| 382 | + kvSTileSizeAct = gatheredKvSeqlen - gatheredKvSTileIdxDe * kvBaseTile_; | ||
| 383 | + } else { | ||
| 384 | + kvSTileSizeAct = kvBaseTile_; | ||
| 385 | + } | ||
| 386 | + // PV | ||
| 387 | + GemmCoord actualBlockShapePV{rowNum, embed_, kvSTileSizeAct}; | ||
| 388 | + uint32_t ubOTmpBufId = gatheredKvSTileIdxDe % UB_S_OTMP_BUF_STAGES; | ||
| 389 | + // 核间同步flagId规律:每份dst对应一个id,从小到大顺序依次为qk->sm, sm->pv, pv->re | ||
| 390 | + uint32_t Mm2ToReFlagId = ubOTmpBufId + UB_S_OTMP_BUF_STAGES + pL1BufNum_; | ||
| 391 | + | ||
| 392 | + uint32_t l1PBufId = gatheredKvSTileIdxDe % pL1BufNum_; | ||
| 393 | + auto ubOTmpLayoutTla = tla::MakeLayout<ElementOTmp, LayoutOTmp>(rowNumRound, embedRound); | ||
| 394 | + auto ubOTmpTensorTla = tla::MakeTensor(ubOTmpTensor[ubOTmpBufId], | ||
| 395 | + ubOTmpLayoutTla, Arch::PositionUB{}); | ||
| 396 | + uint32_t smToMm2FlagId = l1PBufId + UB_S_OTMP_BUF_STAGES; | ||
| 397 | + | ||
| 398 | + Arch::CrossCoreFlag smToMm2Flag(smToMm2FlagId); | ||
| 399 | + Arch::CrossCoreFlag mm2ToReFlag(Mm2ToReFlagId); | ||
| 400 | + uint64_t prefixSumL0AStages = CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 401 | + gatheredKvSTileIdxDe, mm1L0ATotalStages_, mm2L0ATotalStages_, kvSLoopNum, false); | ||
| 402 | + uint64_t prefixSumL0BStages = CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 403 | + gatheredKvSTileIdxDe, mm1L0BTotalStages_, mm2L0BTotalStages_, kvSLoopNum, false); | ||
| 404 | + if (pvStaticNLoopNum == 1) { | ||
| 405 | + blockMmadPV.template operator()<1, 1>( | ||
| 406 | + gmVTensorTla, ubOTmpTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 407 | + actualBlockShapePV, | ||
| 408 | + gatheredKvSTileIdxDe, kvSeqlen, | ||
| 409 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 410 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 411 | + smToMm2Flag, mm2ToReFlag); | ||
| 412 | + } else if (pvStaticNLoopNum == 2) { | ||
| 413 | + blockMmadPV.template operator()<1, 2>( | ||
| 414 | + gmVTensorTla, ubOTmpTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 415 | + actualBlockShapePV, | ||
| 416 | + gatheredKvSTileIdxDe, kvSeqlen, | ||
| 417 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 418 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 419 | + smToMm2Flag, mm2ToReFlag); | ||
| 420 | + } else { | ||
| 421 | + blockMmadPV.template operator()<-1, -1>( | ||
| 422 | + gmVTensorTla, ubOTmpTensorTla, gSparseIdx[gmOffsetSparseIdx], | ||
| 423 | + actualBlockShapePV, | ||
| 424 | + gatheredKvSTileIdxDe, kvSeqlen, | ||
| 425 | + kvBaseTile_, blockShapeY_, yBlockNumAval, yBlockNumRsvd, | ||
| 426 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 427 | + smToMm2Flag, mm2ToReFlag); | ||
| 428 | + } | ||
| 429 | + | ||
| 430 | + | ||
| 431 | + // rescale O | ||
| 432 | + Arch::CrossCoreFlag mm2ToReFlag(Mm2ToReFlagId); | ||
| 433 | + uint32_t curTileMod = gatheredKvSTileIdxDe % (PRE_LAUNCH + 1); | ||
| 434 | + epilogueRescaleO( | ||
| 435 | + gO[gmOffsetO], actualBlockShapePV, | ||
| 436 | + curTileMod, gatheredKvSTileIdxDe, | ||
| 437 | + (gatheredKvSTileIdxDe == 0), | ||
| 438 | + (gatheredKvSTileIdxDe == kvSLoopNum - 1), | ||
| 439 | + mm2ToReFlag); | ||
| 440 | + | ||
| 441 | + } | ||
| 442 | + } | ||
| 443 | + } | ||
| 444 | + // release reverse sync flags | ||
| 445 | + ReleaseSyncFlags<4, 4, 4>(); | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + __aicore__ inline | ||
| 449 | + void FetchBaseShapeInfo(__gm__ EagleQuantBlockSparseAttentionTilingData *bsaTilingData) | ||
| 450 | + { | ||
| 451 | + batch_ = bsaTilingData->batch; | ||
| 452 | + qHeads_ = bsaTilingData->numHeads; | ||
| 453 | + kvHeads_ = bsaTilingData->kvHeads; | ||
| 454 | + embed_ = bsaTilingData->embeddingSize; | ||
| 455 | + firstBatchTaskNum_ = bsaTilingData->firstBatchTaskNum; | ||
| 456 | + totalTaskNum_ = bsaTilingData->totalTaskNum; | ||
| 457 | + blockShapeX_ = bsaTilingData->blockShapeX; | ||
| 458 | + blockShapeY_ = bsaTilingData->blockShapeY; | ||
| 459 | + scaleValue_ = bsaTilingData->scaleValue; | ||
| 460 | + // mask2idx tile info | ||
| 461 | + xBlockNumAligned_ = bsaTilingData->BsaMask2IdxTileInfo.xBlockNumAligned; | ||
| 462 | + yBlockNumAligned_ = bsaTilingData->BsaMask2IdxTileInfo.yBlockNumAligned; | ||
| 463 | + avgRowPerSubCore_ = bsaTilingData->BsaMask2IdxTileInfo.avgRowPerSubCore; | ||
| 464 | + preActiveSubCoreNum_ = bsaTilingData->BsaMask2IdxTileInfo.preActiveSubCoreNum; | ||
| 465 | + // base tile info | ||
| 466 | + qBaseTile_ = bsaTilingData->BsaBaseTileInfo.qBaseTile; | ||
| 467 | + kvBaseTile_ = bsaTilingData->BsaBaseTileInfo.kvBaseTile; | ||
| 468 | + // whether actual seqlen is provided | ||
| 469 | + actSeqAval_ = (!bsaTilingData->useUniformQSeqlen) && (!bsaTilingData->useUniformKvSeqlen); | ||
| 470 | + sparseIdxSize_ = bsaTilingData->selectIdxSize; | ||
| 471 | + // aligned seqlen q & kv | ||
| 472 | + qSeqlenAligned_ = bsaTilingData->maxQSeqlen; | ||
| 473 | + kvSeqlenAligned_ = bsaTilingData->maxKvSeqlen; | ||
| 474 | + } | ||
| 475 | + | ||
| 476 | + __aicore__ inline | ||
| 477 | + void CalcOnChipBufTileInfo(__gm__ EagleQuantBlockSparseAttentionTilingData *bsaTilingData) | ||
| 478 | + { | ||
| 479 | + mm1L1TileM_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm1L1TileM; | ||
| 480 | + mm1L1TileN_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm1L1TileN; | ||
| 481 | + mm1L1TileKLeft_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm1L1TileKLeft; | ||
| 482 | + mm1L1TileKRight_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm1L1TileKRight; | ||
| 483 | + mm2L1TileM_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm2L1TileM; | ||
| 484 | + mm2L1TileN_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm2L1TileN; | ||
| 485 | + mm2L1TileKLeft_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm2L1TileKLeft; | ||
| 486 | + mm2L1TileKRight_ = bsaTilingData->BsaMmPhaseL1TileInfo.mm2L1TileKRight; | ||
| 487 | + qL1BufNum_ = bsaTilingData->BsaMmPhaseL1TileInfo.qL1BufNum; | ||
| 488 | + kL1BufNum_ = bsaTilingData->BsaMmPhaseL1TileInfo.kL1BufNum; | ||
| 489 | + vL1BufNum_ = bsaTilingData->BsaMmPhaseL1TileInfo.vL1BufNum; | ||
| 490 | + pL1BufNum_ = bsaTilingData->BsaMmPhaseL1TileInfo.pL1BufNum; | ||
| 491 | + Gemm::Block::Mm1L1TileHelper mm1L1TileHelper(mm1L1TileM_, mm1L1TileN_, mm1L1TileKLeft_, mm1L1TileKRight_, | ||
| 492 | + qL1BufNum_, kL1BufNum_); | ||
| 493 | + mm1L1TileHelper_ = mm1L1TileHelper; | ||
| 494 | + Gemm::Block::Mm2L1TileHelper mm2L1TileHelper(mm2L1TileM_, mm2L1TileN_, mm2L1TileKLeft_, mm2L1TileKRight_, | ||
| 495 | + pL1BufNum_, vL1BufNum_); | ||
| 496 | + mm2L1TileHelper_ = mm2L1TileHelper; | ||
| 497 | + mm2L1AddrStart_ = mm1L1TileM_ * mm1L1TileKLeft_ * qL1BufNum_ * sizeof(ElementQ) + | ||
| 498 | + mm1L1TileKRight_ * mm1L1TileN_ * kL1BufNum_ * sizeof(ElementK); | ||
| 499 | + mm1L0ATotalStages_ = (qBaseTile_ / BlockMmadQK::L0_TILE_M) * (embed_ / BlockMmadQK::L0_TILE_K); | ||
| 500 | + mm1L0BTotalStages_ = (kvBaseTile_ / BlockMmadQK::L0_TILE_N) * (embed_ / BlockMmadQK::L0_TILE_K); | ||
| 501 | + mm2L0ATotalStages_ = (qBaseTile_ / BlockMmadPV::L0_TILE_M) * (kvBaseTile_ / BlockMmadPV::L0_TILE_K); | ||
| 502 | + mm2L0BTotalStages_ = (kvBaseTile_ / BlockMmadPV::L0_TILE_K) * (embed_ / BlockMmadPV::L0_TILE_N); | ||
| 503 | + } | ||
| 504 | + | ||
| 505 | + __aicore__ inline | ||
| 506 | + uint64_t CalcCrossMm1Mm2PrefixSumL0ABStages( | ||
| 507 | + uint32_t gatheredKvSTileIdx, uint32_t singleMm1L0Stages, | ||
| 508 | + uint32_t singleMm2L0Stages, uint32_t kvSLoopNum, | ||
| 509 | + bool isCurPhaseMm1) | ||
| 510 | + { | ||
| 511 | + uint64_t prefixSumStages; | ||
| 512 | + if (isCurPhaseMm1) { | ||
| 513 | + prefixSumStages = (gatheredKvSTileIdx <= PRE_LAUNCH) ? | ||
| 514 | + gatheredKvSTileIdx * singleMm1L0Stages : | ||
| 515 | + gatheredKvSTileIdx * singleMm1L0Stages + (gatheredKvSTileIdx - PRE_LAUNCH) * singleMm2L0Stages; | ||
| 516 | + } else { | ||
| 517 | + prefixSumStages = (gatheredKvSTileIdx < kvSLoopNum - PRE_LAUNCH) ? | ||
| 518 | + (gatheredKvSTileIdx + 1 + PRE_LAUNCH) * singleMm1L0Stages + gatheredKvSTileIdx * singleMm2L0Stages: | ||
| 519 | + kvSLoopNum * singleMm1L0Stages + gatheredKvSTileIdx * singleMm2L0Stages; | ||
| 520 | + } | ||
| 521 | + return prefixSumStages; | ||
| 522 | + } | ||
| 523 | + | ||
| 524 | + __aicore__ inline | ||
| 525 | + void InitCrossCoreDstBuf( | ||
| 526 | + AscendC::LocalTensor<ElementP> (&l1PTensor)[MAX_CROSS_CORE_BUF_STAGES], | ||
| 527 | + AscendC::LocalTensor<ElementS> (&ubSTensor)[UB_S_OTMP_BUF_STAGES], | ||
| 528 | + AscendC::LocalTensor<ElementOTmp> (&ubOTmpTensor)[UB_S_OTMP_BUF_STAGES]) | ||
| 529 | + { | ||
| 530 | + for (uint32_t i = 0; i < pL1BufNum_; i++) { | ||
| 531 | + l1PTensor[i] = resource.l1Buf.template GetBufferByByte<ElementP>( | ||
| 532 | + mm2L1AddrStart_ + mm2L1TileM_ * mm2L1TileKLeft_ * sizeof(ElementP) * i); | ||
| 533 | + } | ||
| 534 | + uint32_t rowNumPerSubCore = EpilogueOnlineSoftmax::SM_ROW_MAX_ELEM_NUM; | ||
| 535 | + uint32_t colNumPerSubCore = EpilogueOnlineSoftmax::SM_COL_MAX_ELEM_NUM; | ||
| 536 | + uint32_t rescaleCol = EpilogueRescaleO::RESCALE_COL_MAX_ELEM_NUM; | ||
| 537 | + for (uint32_t i = 0; i < UB_S_OTMP_BUF_STAGES; i++) { | ||
| 538 | + ubSTensor[i] = resource.ubBuf.template GetBufferByByte<ElementS>( | ||
| 539 | + rowNumPerSubCore * colNumPerSubCore * sizeof(ElementS) * i); | ||
| 540 | + ubOTmpTensor[i] = resource.ubBuf.template GetBufferByByte<ElementOTmp>( | ||
| 541 | + rowNumPerSubCore * colNumPerSubCore * sizeof(ElementS) * UB_S_OTMP_BUF_STAGES + | ||
| 542 | + rowNumPerSubCore * colNumPerSubCore * sizeof(ElementS) * UB_S_OTMP_BUF_STAGES + | ||
| 543 | + rowNumPerSubCore * rescaleCol * sizeof(ElementOTmp) * i); | ||
| 544 | + } | ||
| 545 | + } | ||
| 546 | + | ||
| 547 | + template <uint32_t MM1_SM_MODE, uint32_t MM2_RE_MODE, uint32_t SM_MM2_MODE> | ||
| 548 | + __aicore__ inline | ||
| 549 | + void InitSyncFlags() | ||
| 550 | + { | ||
| 551 | + | ||
| 552 | + // same core sync between pipes | ||
| 553 | + // Query | ||
| 554 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 555 | + // Key | ||
| 556 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID1); | ||
| 557 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID2); | ||
| 558 | + // Value | ||
| 559 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID3); | ||
| 560 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID4); | ||
| 561 | + // L0A | ||
| 562 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID0); | ||
| 563 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID1); | ||
| 564 | + // L0B | ||
| 565 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID2); | ||
| 566 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID3); | ||
| 567 | + // L0C | ||
| 568 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID0); | ||
| 569 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID1); | ||
| 570 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID2); | ||
| 571 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID3); | ||
| 572 | + // VSDB (L1 Value Scale Double Buffer) | ||
| 573 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_FIX>(EVENT_ID0); | ||
| 574 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_FIX>(EVENT_ID1); | ||
| 575 | + AscendC::SetFlag<AscendC::HardEvent::FIX_MTE2>(EVENT_ID0); | ||
| 576 | + // cross core sync | ||
| 577 | + if constexpr (SM_MM2_MODE == 4U) { | ||
| 578 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(2); | ||
| 579 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(18); | ||
| 580 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(3); | ||
| 581 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(19); | ||
| 582 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(4); | ||
| 583 | + AscendC::CrossCoreSetFlag<SM_MM2_MODE, PIPE_MTE1>(20); | ||
| 584 | + } | ||
| 585 | + | ||
| 586 | + | ||
| 587 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 588 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID1); | ||
| 589 | + // mask2index | ||
| 590 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID0); | ||
| 591 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID1); | ||
| 592 | + // softmax | ||
| 593 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID2); | ||
| 594 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID3); | ||
| 595 | + // rescale | ||
| 596 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 597 | + | ||
| 598 | + AscendC::SetFlag<AscendC::HardEvent::S_MTE3>(EVENT_ID0); | ||
| 599 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(EVENT_ID0); | ||
| 600 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(EVENT_ID1); | ||
| 601 | + if constexpr (MM1_SM_MODE == 4U) { | ||
| 602 | + AscendC::CrossCoreSetFlag<MM1_SM_MODE, PIPE_V>(0); | ||
| 603 | + AscendC::CrossCoreSetFlag<MM1_SM_MODE, PIPE_V>(1); | ||
| 604 | + } | ||
| 605 | + if constexpr (MM2_RE_MODE == 4U) { | ||
| 606 | + AscendC::CrossCoreSetFlag<MM2_RE_MODE, PIPE_V>(5); | ||
| 607 | + AscendC::CrossCoreSetFlag<MM2_RE_MODE, PIPE_V>(6); | ||
| 608 | + } | ||
| 609 | + | ||
| 610 | + } | ||
| 611 | + | ||
| 612 | + template <uint32_t MM1_SM_MODE, uint32_t MM2_RE_MODE, uint32_t SM_MM2_MODE> | ||
| 613 | + __aicore__ inline | ||
| 614 | + void ReleaseSyncFlags() | ||
| 615 | + { | ||
| 616 | + | ||
| 617 | + // same core sync between pipes | ||
| 618 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 619 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID1); | ||
| 620 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID2); | ||
| 621 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID3); | ||
| 622 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID4); | ||
| 623 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID0); | ||
| 624 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID1); | ||
| 625 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID2); | ||
| 626 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID3); | ||
| 627 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID0); | ||
| 628 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID1); | ||
| 629 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID2); | ||
| 630 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID3); | ||
| 631 | + // VSDB (L1 Value Scale Double Buffer) | ||
| 632 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_FIX>(EVENT_ID0); | ||
| 633 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_FIX>(EVENT_ID1); | ||
| 634 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_MTE2>(EVENT_ID0); | ||
| 635 | + if constexpr (MM1_SM_MODE == 4U) { | ||
| 636 | + AscendC::CrossCoreWaitFlag<MM1_SM_MODE, PIPE_FIX>(0); | ||
| 637 | + AscendC::CrossCoreWaitFlag<MM1_SM_MODE, PIPE_FIX>(1); | ||
| 638 | + AscendC::CrossCoreWaitFlag<MM1_SM_MODE, PIPE_FIX>(16); | ||
| 639 | + AscendC::CrossCoreWaitFlag<MM1_SM_MODE, PIPE_FIX>(17); | ||
| 640 | + } | ||
| 641 | + if constexpr (MM2_RE_MODE == 4U) { | ||
| 642 | + AscendC::CrossCoreWaitFlag<MM2_RE_MODE, PIPE_FIX>(5); | ||
| 643 | + AscendC::CrossCoreWaitFlag<MM2_RE_MODE, PIPE_FIX>(21); | ||
| 644 | + AscendC::CrossCoreWaitFlag<MM2_RE_MODE, PIPE_FIX>(6); | ||
| 645 | + AscendC::CrossCoreWaitFlag<MM2_RE_MODE, PIPE_FIX>(22); | ||
| 646 | + } | ||
| 647 | + | ||
| 648 | + | ||
| 649 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 650 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID1); | ||
| 651 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID0); | ||
| 652 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID1); | ||
| 653 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID2); | ||
| 654 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID3); | ||
| 655 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 656 | + AscendC::WaitFlag<AscendC::HardEvent::S_MTE3>(EVENT_ID0); | ||
| 657 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(EVENT_ID0); | ||
| 658 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(EVENT_ID1); | ||
| 659 | + if constexpr (SM_MM2_MODE == 4U) { | ||
| 660 | + AscendC::CrossCoreWaitFlag<SM_MM2_MODE, PIPE_MTE3>(2); | ||
| 661 | + AscendC::CrossCoreWaitFlag<SM_MM2_MODE, PIPE_MTE3>(3); | ||
| 662 | + AscendC::CrossCoreWaitFlag<SM_MM2_MODE, PIPE_MTE3>(4); | ||
| 663 | + } | ||
| 664 | + | ||
| 665 | + AscendC::PipeBarrier<PIPE_ALL>(); | ||
| 666 | + } | ||
| 667 | + | ||
| 668 | +private: | ||
| 669 | + Arch::Resource<ArchTag> resource; | ||
| 670 | + /* | ||
| 671 | + tiling info, which are const in each kernel launch | ||
| 672 | + */ | ||
| 673 | + // basic shape info | ||
| 674 | + uint32_t batch_; | ||
| 675 | + uint32_t qHeads_; | ||
| 676 | + uint32_t kvHeads_; | ||
| 677 | + uint32_t embed_; | ||
| 678 | + uint32_t firstBatchTaskNum_; | ||
| 679 | + uint32_t totalTaskNum_; | ||
| 680 | + uint32_t blockShapeX_; | ||
| 681 | + uint32_t blockShapeY_; | ||
| 682 | + float scaleValue_; | ||
| 683 | + // mask2idx tile info | ||
| 684 | + uint32_t xBlockNumAligned_; | ||
| 685 | + uint32_t yBlockNumAligned_; | ||
| 686 | + uint32_t avgRowPerSubCore_; | ||
| 687 | + uint32_t preActiveSubCoreNum_; | ||
| 688 | + // base tile info | ||
| 689 | + uint32_t qBaseTile_; | ||
| 690 | + uint32_t kvBaseTile_; | ||
| 691 | + // whether actual seqlen is provided | ||
| 692 | + uint32_t actSeqAval_; | ||
| 693 | + // workspace size | ||
| 694 | + uint64_t sparseIdxSize_; | ||
| 695 | + // aligned seqlen q & kv | ||
| 696 | + int64_t qSeqlenAligned_; | ||
| 697 | + int64_t kvSeqlenAligned_; | ||
| 698 | + // L1 tile info | ||
| 699 | + uint32_t mm1L1TileM_; | ||
| 700 | + uint32_t mm1L1TileN_; | ||
| 701 | + uint32_t mm1L1TileKLeft_; | ||
| 702 | + uint32_t mm1L1TileKRight_; | ||
| 703 | + uint32_t mm2L1TileM_; | ||
| 704 | + uint32_t mm2L1TileN_; | ||
| 705 | + uint32_t mm2L1TileKLeft_; | ||
| 706 | + uint32_t mm2L1TileKRight_; | ||
| 707 | + uint32_t qL1BufNum_; | ||
| 708 | + uint32_t kL1BufNum_; | ||
| 709 | + uint32_t vL1BufNum_; | ||
| 710 | + uint32_t pL1BufNum_; | ||
| 711 | + uint32_t mm1L0ATotalStages_; | ||
| 712 | + uint32_t mm1L0BTotalStages_; | ||
| 713 | + uint32_t mm2L0ATotalStages_; | ||
| 714 | + uint32_t mm2L0BTotalStages_; | ||
| 715 | + uint32_t mm2L1AddrStart_ = 0; | ||
| 716 | + Gemm::Block::Mm1L1TileHelper mm1L1TileHelper_; | ||
| 717 | + Gemm::Block::Mm2L1TileHelper mm2L1TileHelper_; | ||
| 718 | +}; | ||
| 719 | + | ||
| 720 | +} | ||
| 721 | + | ||
| 722 | + | ||
| @@ -0,0 +1,230 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +namespace BsaKernelArch35 { | ||
| 32 | + | ||
| 33 | +enum class Format { | ||
| 34 | + TND = 0, | ||
| 35 | + BNSD = 1 | ||
| 36 | +}; | ||
| 37 | + | ||
| 38 | +struct BsaKernelParamsArch35 { | ||
| 39 | + GM_ADDR q; | ||
| 40 | + GM_ADDR k; | ||
| 41 | + GM_ADDR v; | ||
| 42 | + GM_ADDR mask; | ||
| 43 | + GM_ADDR blockTables; | ||
| 44 | + GM_ADDR query_scale; | ||
| 45 | + GM_ADDR key_scale; | ||
| 46 | + GM_ADDR value_scale; | ||
| 47 | + GM_ADDR actualQseqlen; | ||
| 48 | + GM_ADDR actualKvseqlen; | ||
| 49 | + GM_ADDR blockSparseMask; | ||
| 50 | + GM_ADDR o; | ||
| 51 | + GM_ADDR workSpace; | ||
| 52 | + GM_ADDR tiling; | ||
| 53 | + | ||
| 54 | + // Methods | ||
| 55 | + __aicore__ inline | ||
| 56 | + BsaKernelParamsArch35() {} | ||
| 57 | + __aicore__ inline | ||
| 58 | + BsaKernelParamsArch35(GM_ADDR q_, GM_ADDR k_, GM_ADDR v_, GM_ADDR mask_, GM_ADDR blockTables_, | ||
| 59 | + GM_ADDR query_scale_, GM_ADDR key_scale_, GM_ADDR value_scale_, | ||
| 60 | + GM_ADDR actualQseqlen_, GM_ADDR actualKvseqlen_, GM_ADDR blockSparseMask_, GM_ADDR o_, | ||
| 61 | + GM_ADDR workSpace_, GM_ADDR tiling_) | ||
| 62 | + : q(q_), k(k_), v(v_), mask(mask_), blockTables(blockTables_), actualQseqlen(actualQseqlen_), | ||
| 63 | + query_scale(query_scale_), key_scale(key_scale_), value_scale(value_scale_), | ||
| 64 | + actualKvseqlen(actualKvseqlen_), blockSparseMask(blockSparseMask_), o(o_), | ||
| 65 | + workSpace(workSpace_), tiling(tiling_) {} | ||
| 66 | +}; | ||
| 67 | + | ||
| 68 | +constexpr uint32_t SPARSE_PATTERN_MODE_TABLE = 1; | ||
| 69 | + | ||
| 70 | + | ||
| 71 | +template<class ArchTag> | ||
| 72 | +__aicore__ inline void SparseTable2Count( | ||
| 73 | + NpuArch::Arch::Resource<ArchTag> &resource, | ||
| 74 | + AscendC::GlobalTensor<int32_t> sparseTableGM, | ||
| 75 | + AscendC::GlobalTensor<int32_t> sparseCountGM, | ||
| 76 | + uint32_t totalRowNumBlockMask, | ||
| 77 | + uint32_t yBlockNumAligned, | ||
| 78 | + uint32_t avgRowPerSubCore, | ||
| 79 | + uint32_t preActiveSubCoreNum) | ||
| 80 | +{ | ||
| 81 | + static constexpr uint32_t PRE_ROW_TILE = 128; | ||
| 82 | + static constexpr uint32_t PRE_COL_TILE = 128; | ||
| 83 | + static constexpr uint32_t PRE_ELEM_NUM_PER_LOOP = PRE_ROW_TILE * PRE_COL_TILE; | ||
| 84 | + static constexpr uint32_t TABLE_IN_INT32 = 0; | ||
| 85 | + static constexpr uint32_t TABLE_VALID_BIT = TABLE_IN_INT32 + PRE_ELEM_NUM_PER_LOOP * sizeof(int32_t); | ||
| 86 | + static constexpr uint32_t TABLE_ONE_VALUE = TABLE_VALID_BIT + PRE_COL_TILE * sizeof(uint8_t); | ||
| 87 | + static constexpr uint32_t TABLE_VALID_VALUE = TABLE_ONE_VALUE + PRE_COL_TILE * sizeof(float); | ||
| 88 | + static constexpr uint32_t TABLE_TILE_COUNT = TABLE_VALID_VALUE + PRE_ELEM_NUM_PER_LOOP * sizeof(float); | ||
| 89 | + static constexpr uint32_t TABLE_COUNT_FLOAT = TABLE_TILE_COUNT + PRE_ROW_TILE * sizeof(float); | ||
| 90 | + static constexpr uint32_t RSVD_SPARSE_COUNT = TABLE_COUNT_FLOAT + PRE_ROW_TILE * sizeof(float); | ||
| 91 | + // Pass Sum an explicit temp buffer so it will not pop hidden UB space outside this layout. | ||
| 92 | + static constexpr uint32_t TABLE_SUM_TMP = RSVD_SPARSE_COUNT + PRE_ROW_TILE * sizeof(int32_t); | ||
| 93 | + static constexpr uint32_t TABLE_SUM_TMP_SIZE = PRE_ROW_TILE * PRE_COL_TILE * sizeof(float); | ||
| 94 | + static constexpr uint32_t SPARSE_TABLE_UB_SIZE = TABLE_SUM_TMP + TABLE_SUM_TMP_SIZE; | ||
| 95 | + static constexpr uint32_t SPARSE_TABLE_UB_LIMIT = ArchTag::UB_SIZE - 8U * 1024U; | ||
| 96 | + static constexpr int32_t SPARSE_TABLE_END = -1; | ||
| 97 | + static constexpr int32_t SPARSE_TABLE_VALID_MIN = 0; | ||
| 98 | + static_assert(SPARSE_TABLE_UB_SIZE <= SPARSE_TABLE_UB_LIMIT, | ||
| 99 | + "SparseTable2Count UB layout exceeds the usable arch UB size."); | ||
| 100 | + | ||
| 101 | + AscendC::LocalTensor<int32_t> sparseTableUb = | ||
| 102 | + resource.ubBuf.template GetBufferByByte<int32_t>(TABLE_IN_INT32);//128*128*4Bytes | ||
| 103 | + AscendC::LocalTensor<uint8_t> validMaskUb = | ||
| 104 | + resource.ubBuf.template GetBufferByByte<uint8_t>(TABLE_VALID_BIT);//128Bytes | ||
| 105 | + AscendC::LocalTensor<float> oneValueUb = | ||
| 106 | + resource.ubBuf.template GetBufferByByte<float>(TABLE_ONE_VALUE);//128*4Bytes | ||
| 107 | + AscendC::LocalTensor<float> validValueUb = | ||
| 108 | + resource.ubBuf.template GetBufferByByte<float>(TABLE_VALID_VALUE);//128*128*4Bytes | ||
| 109 | + AscendC::LocalTensor<float> tileCountUb = | ||
| 110 | + resource.ubBuf.template GetBufferByByte<float>(TABLE_TILE_COUNT);//128*4Bytes | ||
| 111 | + AscendC::LocalTensor<float> countFloatUb = | ||
| 112 | + resource.ubBuf.template GetBufferByByte<float>(TABLE_COUNT_FLOAT);//128*4Bytes | ||
| 113 | + AscendC::LocalTensor<int32_t> sparseCountUb = | ||
| 114 | + resource.ubBuf.template GetBufferByByte<int32_t>(RSVD_SPARSE_COUNT);//128*4Bytes | ||
| 115 | + AscendC::LocalTensor<uint8_t> sumTmpUb = | ||
| 116 | + resource.ubBuf.template GetBufferByByte<uint8_t>(TABLE_SUM_TMP);//128*128*4Bytes | ||
| 117 | + | ||
| 118 | + uint32_t subCoreIdx = AscendC::GetBlockIdx(); | ||
| 119 | + uint64_t curSubCoreRowOffset = static_cast<uint64_t>(subCoreIdx) * avgRowPerSubCore; | ||
| 120 | + uint32_t actDealtRow = (subCoreIdx == preActiveSubCoreNum - 1) ? | ||
| 121 | + static_cast<uint32_t>(totalRowNumBlockMask - curSubCoreRowOffset) : avgRowPerSubCore; | ||
| 122 | + if (subCoreIdx >= preActiveSubCoreNum) { | ||
| 123 | + return; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + AscendC::Duplicate(oneValueUb, static_cast<float>(1.0), PRE_COL_TILE); | ||
| 127 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 128 | + uint32_t rowLoop = (actDealtRow + PRE_ROW_TILE - 1) / PRE_ROW_TILE; | ||
| 129 | + for (uint32_t i = 0; i < rowLoop; i++) { | ||
| 130 | + uint32_t curLoopRowOffset = i * PRE_ROW_TILE; | ||
| 131 | + uint32_t actDealtRowCurLoop = | ||
| 132 | + (i == rowLoop - 1) ? (actDealtRow - curLoopRowOffset) : PRE_ROW_TILE; | ||
| 133 | + | ||
| 134 | + AscendC::Duplicate(countFloatUb, static_cast<float>(0.0), actDealtRowCurLoop); | ||
| 135 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 136 | + uint32_t colLoop = (yBlockNumAligned + PRE_COL_TILE - 1) / PRE_COL_TILE; | ||
| 137 | + for (uint32_t j = 0; j < colLoop; j++) { | ||
| 138 | + uint32_t curLoopColOffset = j * PRE_COL_TILE; | ||
| 139 | + uint32_t actDealtColCurLoop = | ||
| 140 | + (j == colLoop - 1) ? (yBlockNumAligned - curLoopColOffset) : PRE_COL_TILE; | ||
| 141 | + // MTE copy only needs 32B alignment; CompareScalar keeps the 256B count alignment. | ||
| 142 | + uint32_t actDealtColCurLoopCopyAlign = ((actDealtColCurLoop + 7) / 8) * 8; | ||
| 143 | + uint32_t actDealtColCurLoopCompareAlign = ((actDealtColCurLoop + 63) / 64) * 64; | ||
| 144 | + uint32_t copyRightPadding = actDealtColCurLoopCopyAlign - actDealtColCurLoop; | ||
| 145 | + uint64_t sparseTableOffset = | ||
| 146 | + (curSubCoreRowOffset + curLoopRowOffset) * yBlockNumAligned + curLoopColOffset; | ||
| 147 | + | ||
| 148 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(0); | ||
| 149 | + if (actDealtColCurLoopCompareAlign > actDealtColCurLoopCopyAlign) { | ||
| 150 | + // Pre-fill the compare-only tail. This avoids large MTE right-padding configs. | ||
| 151 | + AscendC::Duplicate(sparseTableUb, SPARSE_TABLE_END, actDealtRowCurLoop * PRE_COL_TILE); | ||
| 152 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 153 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(0); | ||
| 154 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(0); | ||
| 155 | + } | ||
| 156 | + // Load one int32 sparse-table tile. MTE pads only to 32B; any wider compare tail is already -1. | ||
| 157 | + AscendC::DataCopyPad( | ||
| 158 | + sparseTableUb, | ||
| 159 | + sparseTableGM[sparseTableOffset], | ||
| 160 | + AscendC::DataCopyExtParams( | ||
| 161 | + actDealtRowCurLoop, //BlockCount 指定该指令包含的连续传输数据块的个数 | ||
| 162 | + actDealtColCurLoop * sizeof(int32_t), //指定该指令每个连续传输数据块长度,单位为字节 | ||
| 163 | + (yBlockNumAligned - actDealtColCurLoop) * sizeof(int32_t), //源操作数相邻连续数据块间隔(从前一个尾到后一个头),单位为字节 | ||
| 164 | + (PRE_COL_TILE - actDealtColCurLoopCopyAlign) * sizeof(int32_t) / 32,//目的操作数相邻连续数据块间隔(从前一个尾到后一个头),单位为32B | ||
| 165 | + 0), | ||
| 166 | + //isPad表示要填充 leftPadding,左侧需要填充的元素个数,字节数不要超过32B,rightPadding,右侧要填充元素个数,不超过32B,PaddingValue是要填充的数值 | ||
| 167 | + AscendC::DataCopyPadExtParams<int32_t>( | ||
| 168 | + true, 0, copyRightPadding, SPARSE_TABLE_END)); | ||
| 169 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(0); | ||
| 170 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(0); | ||
| 171 | + for (uint32_t row = 0; row < actDealtRowCurLoop; row++) { | ||
| 172 | + // Sparse table rows are terminated by -1; valid table indices are non-negative. | ||
| 173 | + AscendC::CompareScalar( | ||
| 174 | + validMaskUb,//输出,目的操作数 | ||
| 175 | + sparseTableUb[row * PRE_COL_TILE],//源操作数0 | ||
| 176 | + SPARSE_TABLE_VALID_MIN, | ||
| 177 | + AscendC::CMPMODE::GE, | ||
| 178 | + actDealtColCurLoopCompareAlign);//calCount,输入数据元素个数,设置CalCount时,需要保证calCount个元素所占空间256字节对齐 | ||
| 179 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 180 | + //Mask数值为0,从src0选取,否则从src1中选取 | ||
| 181 | + AscendC::Select( | ||
| 182 | + validValueUb[row * PRE_COL_TILE],//输出 | ||
| 183 | + validMaskUb,//mask输入 | ||
| 184 | + oneValueUb,//源操作数0 | ||
| 185 | + static_cast<float>(0.0),//源操作数1 | ||
| 186 | + AscendC::SELMODE::VSEL_TENSOR_SCALAR_MODE, //selMode | ||
| 187 | + actDealtColCurLoopCompareAlign); //calCount | ||
| 188 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 189 | + } | ||
| 190 | + AscendC::Sum( | ||
| 191 | + tileCountUb, | ||
| 192 | + validValueUb, | ||
| 193 | + sumTmpUb, | ||
| 194 | + AscendC::SumParams{actDealtRowCurLoop, PRE_COL_TILE, actDealtColCurLoop}); | ||
| 195 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 196 | + AscendC::Add(countFloatUb, countFloatUb, tileCountUb, actDealtRowCurLoop); | ||
| 197 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 198 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(0); | ||
| 199 | + } | ||
| 200 | + AscendC::Cast( | ||
| 201 | + sparseCountUb, | ||
| 202 | + countFloatUb, | ||
| 203 | + AscendC::RoundMode::CAST_ROUND, | ||
| 204 | + actDealtRowCurLoop); | ||
| 205 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 206 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(0); | ||
| 207 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(0); | ||
| 208 | + uint64_t sparseCountOffset = curSubCoreRowOffset + curLoopRowOffset; | ||
| 209 | + AscendC::DataCopyPad( | ||
| 210 | + sparseCountGM[sparseCountOffset], | ||
| 211 | + sparseCountUb, | ||
| 212 | + AscendC::DataCopyExtParams(1, actDealtRowCurLoop * sizeof(int32_t), 0, 0, 0)); | ||
| 213 | + } | ||
| 214 | + | ||
| 215 | +} | ||
| 216 | + | ||
| 217 | +__aicore__ inline | ||
| 218 | +uint32_t GetCurQSTileNum(int64_t curQSeqlen, uint32_t blockShapeX, uint32_t qBaseTile) | ||
| 219 | +{ | ||
| 220 | + uint32_t fullXBlockNum = curQSeqlen / blockShapeX; | ||
| 221 | + uint32_t tailXBlockSize = curQSeqlen % blockShapeX; | ||
| 222 | + uint32_t qSTileNumPerFullXBlock = (blockShapeX + qBaseTile - 1) / qBaseTile; | ||
| 223 | + uint32_t qSTileNumTailXBlock = (tailXBlockSize + qBaseTile - 1) / qBaseTile; | ||
| 224 | + uint32_t curQSTileNum = qSTileNumPerFullXBlock * fullXBlockNum + qSTileNumTailXBlock; | ||
| 225 | + return curQSTileNum; | ||
| 226 | +} | ||
| 227 | + | ||
| 228 | +} | ||
| 229 | + | ||
| 230 | + | ||
| @@ -0,0 +1,51 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace NpuArch::Arch | ||
| 17 | +{ | ||
| 18 | + | ||
| 19 | +struct AtlasA2 { | ||
| 20 | + static constexpr uint32_t BIAS_SIZE = 1024; | ||
| 21 | + static constexpr uint32_t FIXBUF_SIZE = 7U * 1024U; | ||
| 22 | + static constexpr uint32_t UB_SIZE = 192U * 1024U; | ||
| 23 | + static constexpr uint32_t L1_SIZE = 512U * 1024U; | ||
| 24 | + static constexpr uint32_t L0A_SIZE = 64U * 1024U; | ||
| 25 | + static constexpr uint32_t L0B_SIZE = 64U * 1024U; | ||
| 26 | + static constexpr uint32_t L0C_SIZE = 128U * 1024U; | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +struct AtlasA5 { | ||
| 30 | + static constexpr uint32_t BIAS_SIZE = 4U * 1024U; | ||
| 31 | + static constexpr uint32_t FIXBUF_SIZE = 16U * 1024U; | ||
| 32 | + static constexpr uint32_t UB_SIZE = 256U * 1024U; | ||
| 33 | + static constexpr uint32_t L1_SIZE = 512U * 1024U; | ||
| 34 | + static constexpr uint32_t L0A_SIZE = 64U * 1024U; | ||
| 35 | + static constexpr uint32_t L0B_SIZE = 64U * 1024U; | ||
| 36 | + static constexpr uint32_t L0C_SIZE = 256U * 1024U; | ||
| 37 | +}; | ||
| 38 | + | ||
| 39 | +template <AscendC::TPosition POS> | ||
| 40 | +using PositionType = std::integral_constant<AscendC::TPosition, POS>; | ||
| 41 | + | ||
| 42 | +using PositionGM = PositionType<AscendC::TPosition::GM>; | ||
| 43 | +using PositionL1 = PositionType<AscendC::TPosition::A1>; | ||
| 44 | +using PositionL0A = PositionType<AscendC::TPosition::A2>; | ||
| 45 | +using PositionL0B = PositionType<AscendC::TPosition::B2>; | ||
| 46 | +using PositionL0C = PositionType<AscendC::TPosition::CO1>; | ||
| 47 | +using PositionUB = PositionType<AscendC::TPosition::VECCALC>; | ||
| 48 | + | ||
| 49 | +} // namespace NpuArch::Arch | ||
| 50 | + | ||
| 51 | + | ||
| @@ -0,0 +1,116 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace NpuArch::Arch | ||
| 17 | +{ | ||
| 18 | + | ||
| 19 | +constexpr uint32_t MAX_REVERSE_DEPTH = 16; | ||
| 20 | + | ||
| 21 | +using FlagID = uint16_t; | ||
| 22 | +constexpr FlagID AIV_INTER_BLOCK_BARRIER = 8; | ||
| 23 | +constexpr FlagID AIC_INTER_BLOCK_BARRIER = 9; | ||
| 24 | +constexpr FlagID AIV_INTER_SUBBLOCK_BARRIER = 10; | ||
| 25 | +constexpr FlagID FFTS_MAX_FLAG = 7; | ||
| 26 | + | ||
| 27 | +struct CrossCoreFlag { | ||
| 28 | + __aicore__ inline | ||
| 29 | + CrossCoreFlag() : id(0) {} | ||
| 30 | + | ||
| 31 | + __aicore__ inline | ||
| 32 | + CrossCoreFlag(FlagID id) : id(id) {} | ||
| 33 | + | ||
| 34 | + FlagID id; | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +template <uint32_t REVERSE_DEPTH_ = MAX_REVERSE_DEPTH> | ||
| 38 | +struct CrossCoreFlagWithReverse { | ||
| 39 | + __aicore__ inline | ||
| 40 | + CrossCoreFlagWithReverse() : id(0), reverseId(0) {} | ||
| 41 | + | ||
| 42 | + __aicore__ inline | ||
| 43 | + CrossCoreFlagWithReverse(FlagID id, FlagID reverseId) : id(id), reverseId(reverseId) {} | ||
| 44 | + | ||
| 45 | + FlagID id; | ||
| 46 | + FlagID reverseId; | ||
| 47 | + uint32_t count{ 0 }; | ||
| 48 | +}; | ||
| 49 | + | ||
| 50 | +template <uint8_t MODE, int32_t CORE_TYPE> | ||
| 51 | +struct BarrierFlag { | ||
| 52 | + static_assert(MODE != MODE, "Unsupported cross core barrier flag, can not find the specialization."); | ||
| 53 | +}; | ||
| 54 | + | ||
| 55 | +template <> | ||
| 56 | +struct BarrierFlag<0x0, AscendC::AIV> { | ||
| 57 | + static constexpr FlagID ID = AIV_INTER_BLOCK_BARRIER; | ||
| 58 | +}; | ||
| 59 | + | ||
| 60 | +template <> | ||
| 61 | +struct BarrierFlag<0x0, AscendC::AIC> { | ||
| 62 | + static constexpr FlagID ID = AIC_INTER_BLOCK_BARRIER; | ||
| 63 | +}; | ||
| 64 | + | ||
| 65 | +template <> | ||
| 66 | +struct BarrierFlag<0x1, AscendC::AIV> { | ||
| 67 | + static constexpr FlagID ID = AIV_INTER_SUBBLOCK_BARRIER; | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +template <uint8_t MODE, pipe_t PIPE> | ||
| 71 | +__aicore__ inline | ||
| 72 | +void CrossCoreBarrier() | ||
| 73 | +{ | ||
| 74 | + constexpr FlagID flagId = BarrierFlag<MODE, g_coreType>::ID; | ||
| 75 | + AscendC::CrossCoreSetFlag<MODE, PIPE>(flagId); | ||
| 76 | + AscendC::CrossCoreWaitFlag(flagId); | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +template <uint8_t MODE, pipe_t PIPE> | ||
| 80 | +__aicore__ inline | ||
| 81 | +void CrossCoreSetFlag(CrossCoreFlag &flag) | ||
| 82 | +{ | ||
| 83 | + AscendC::CrossCoreSetFlag<MODE, PIPE>(flag.id); | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +template <uint8_t MODE = 0, pipe_t PIPE = PIPE_S> | ||
| 87 | +__aicore__ inline void CrossCoreWaitFlag(CrossCoreFlag &flag) | ||
| 88 | +{ | ||
| 89 | + AscendC::CrossCoreWaitFlag<MODE, PIPE>(flag.id); | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +template <uint8_t MODE, pipe_t PIPE, uint32_t REVERSE_DEPTH> | ||
| 93 | +__aicore__ inline | ||
| 94 | +void CrossCoreSetFlagWithReverse(CrossCoreFlagWithReverse<REVERSE_DEPTH> &flag) | ||
| 95 | +{ | ||
| 96 | + AscendC::CrossCoreSetFlag<MODE, PIPE>(flag.id); | ||
| 97 | + if (++flag.count >= REVERSE_DEPTH) { | ||
| 98 | + AscendC::CrossCoreWaitFlag(flag.reverseId); | ||
| 99 | + flag.count = 0; | ||
| 100 | + } | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +template <uint8_t MODE, pipe_t PIPE, uint32_t REVERSE_DEPTH> | ||
| 104 | +__aicore__ inline | ||
| 105 | +void CrossCoreWaitFlagWithReverse(CrossCoreFlagWithReverse<REVERSE_DEPTH> &flag) | ||
| 106 | +{ | ||
| 107 | + AscendC::CrossCoreWaitFlag(flag.id); | ||
| 108 | + if (++flag.count >= REVERSE_DEPTH) { | ||
| 109 | + AscendC::CrossCoreSetFlag<MODE, PIPE>(flag.reverseId); | ||
| 110 | + flag.count = 0; | ||
| 111 | + } | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +} // namespace NpuArch::Arch | ||
| 115 | + | ||
| 116 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/arch/local_tensor_buffer.hpp+343-0
| @@ -0,0 +1,343 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace NpuArch::Arch | ||
| 18 | +{ | ||
| 19 | + | ||
| 20 | +struct LocalTensorBufferBase { | ||
| 21 | +public: | ||
| 22 | + template <class Element = half> | ||
| 23 | + __aicore__ inline | ||
| 24 | + AscendC::LocalTensor<Element> GetBufferByByte(const uint32_t offset) const | ||
| 25 | + { | ||
| 26 | + return tensor[offset].template ReinterpretCast<Element>(); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +protected: | ||
| 30 | + __aicore__ inline | ||
| 31 | + LocalTensorBufferBase() = default; | ||
| 32 | + | ||
| 33 | + AscendC::LocalTensor<uint8_t> tensor; | ||
| 34 | +}; | ||
| 35 | + | ||
| 36 | +template < | ||
| 37 | + class ArchTag, | ||
| 38 | + AscendC::TPosition Position | ||
| 39 | +> | ||
| 40 | +struct LocalTensorBuffer { | ||
| 41 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported local tensor buffer, can not find the specialization."); | ||
| 42 | +}; | ||
| 43 | + | ||
| 44 | +/// Partial specialization for TPosition::A1 | ||
| 45 | +template <> | ||
| 46 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::A1> : LocalTensorBufferBase { | ||
| 47 | +public: | ||
| 48 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::A1; | ||
| 49 | + | ||
| 50 | + __aicore__ inline | ||
| 51 | + LocalTensorBuffer() | ||
| 52 | + { | ||
| 53 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::A1, 0, Arch::AtlasA5::L1_SIZE); | ||
| 54 | + } | ||
| 55 | +}; | ||
| 56 | + | ||
| 57 | +/////////////////////////////////////////////////////////// | ||
| 58 | + | ||
| 59 | +/// Partial specialization for TPosition::A2 | ||
| 60 | +template <> | ||
| 61 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::A2> : LocalTensorBufferBase { | ||
| 62 | +public: | ||
| 63 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::A2; | ||
| 64 | + | ||
| 65 | + __aicore__ inline | ||
| 66 | + LocalTensorBuffer() | ||
| 67 | + { | ||
| 68 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::A2, 0, Arch::AtlasA5::L0A_SIZE); | ||
| 69 | + } | ||
| 70 | +}; | ||
| 71 | + | ||
| 72 | +/////////////////////////////////////////////////////////// | ||
| 73 | + | ||
| 74 | +/// Partial specialization for TPosition::B1 | ||
| 75 | +template <> | ||
| 76 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::B1> : LocalTensorBufferBase { | ||
| 77 | +public: | ||
| 78 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::B1; | ||
| 79 | + | ||
| 80 | + __aicore__ inline | ||
| 81 | + LocalTensorBuffer() | ||
| 82 | + { | ||
| 83 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::B1, 0, Arch::AtlasA5::L1_SIZE); | ||
| 84 | + } | ||
| 85 | +}; | ||
| 86 | + | ||
| 87 | +/////////////////////////////////////////////////////////// | ||
| 88 | + | ||
| 89 | +/// Partial specialization for TPosition::B2 | ||
| 90 | +template <> | ||
| 91 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::B2> : LocalTensorBufferBase { | ||
| 92 | +public: | ||
| 93 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::B2; | ||
| 94 | + | ||
| 95 | + __aicore__ inline | ||
| 96 | + LocalTensorBuffer() | ||
| 97 | + { | ||
| 98 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::B2, 0, Arch::AtlasA5::L0B_SIZE); | ||
| 99 | + } | ||
| 100 | +}; | ||
| 101 | + | ||
| 102 | +/////////////////////////////////////////////////////////// | ||
| 103 | + | ||
| 104 | +/// Partial specialization for TPosition::C1 | ||
| 105 | +template <> | ||
| 106 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::C1> : LocalTensorBufferBase { | ||
| 107 | +public: | ||
| 108 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::C1; | ||
| 109 | + | ||
| 110 | + __aicore__ inline | ||
| 111 | + LocalTensorBuffer() | ||
| 112 | + { | ||
| 113 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::C1, 0, Arch::AtlasA5::L1_SIZE); | ||
| 114 | + } | ||
| 115 | +}; | ||
| 116 | + | ||
| 117 | +/////////////////////////////////////////////////////////// | ||
| 118 | + | ||
| 119 | +/// Partial specialization for TPosition::C2 | ||
| 120 | +template <> | ||
| 121 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::C2> : LocalTensorBufferBase { | ||
| 122 | +public: | ||
| 123 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::C2; | ||
| 124 | + | ||
| 125 | + __aicore__ inline | ||
| 126 | + LocalTensorBuffer() | ||
| 127 | + { | ||
| 128 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::C2, 0, Arch::AtlasA5::BIAS_SIZE); | ||
| 129 | + } | ||
| 130 | +}; | ||
| 131 | + | ||
| 132 | +/////////////////////////////////////////////////////////// | ||
| 133 | + | ||
| 134 | +/// Partial specialization for TPosition::CO1 | ||
| 135 | +template <> | ||
| 136 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::CO1> : LocalTensorBufferBase { | ||
| 137 | +public: | ||
| 138 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::CO1; | ||
| 139 | + | ||
| 140 | + __aicore__ inline | ||
| 141 | + LocalTensorBuffer() | ||
| 142 | + { | ||
| 143 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::CO1, 0, Arch::AtlasA5::L0C_SIZE); | ||
| 144 | + } | ||
| 145 | +}; | ||
| 146 | + | ||
| 147 | +/////////////////////////////////////////////////////////// | ||
| 148 | + | ||
| 149 | +/// Partial specialization for TPosition::C2PIPE2GM | ||
| 150 | +template <> | ||
| 151 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::C2PIPE2GM> : LocalTensorBufferBase { | ||
| 152 | +public: | ||
| 153 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::C2PIPE2GM; | ||
| 154 | + | ||
| 155 | + __aicore__ inline | ||
| 156 | + LocalTensorBuffer() | ||
| 157 | + { | ||
| 158 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::C2PIPE2GM, 0, Arch::AtlasA5::FIXBUF_SIZE); | ||
| 159 | + } | ||
| 160 | +}; | ||
| 161 | + | ||
| 162 | +/////////////////////////////////////////////////////////// | ||
| 163 | + | ||
| 164 | +/// Partial specialization for TPosition::VECIN | ||
| 165 | +template <> | ||
| 166 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::VECIN> : LocalTensorBufferBase { | ||
| 167 | +public: | ||
| 168 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::VECIN; | ||
| 169 | + | ||
| 170 | + __aicore__ inline | ||
| 171 | + LocalTensorBuffer() | ||
| 172 | + { | ||
| 173 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::VECIN, 0, Arch::AtlasA5::UB_SIZE); | ||
| 174 | + } | ||
| 175 | +}; | ||
| 176 | + | ||
| 177 | +/////////////////////////////////////////////////////////// | ||
| 178 | + | ||
| 179 | +/// Partial specialization for TPosition::VECOUT | ||
| 180 | +template <> | ||
| 181 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::VECOUT> : LocalTensorBufferBase { | ||
| 182 | +public: | ||
| 183 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::VECOUT; | ||
| 184 | + | ||
| 185 | + __aicore__ inline | ||
| 186 | + LocalTensorBuffer() | ||
| 187 | + { | ||
| 188 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::VECOUT, 0, Arch::AtlasA5::UB_SIZE); | ||
| 189 | + } | ||
| 190 | +}; | ||
| 191 | + | ||
| 192 | +/////////////////////////////////////////////////////////// | ||
| 193 | + | ||
| 194 | +/// Partial specialization for TPosition::VECCALC | ||
| 195 | +template <> | ||
| 196 | +struct LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::VECCALC> : LocalTensorBufferBase { | ||
| 197 | +public: | ||
| 198 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::VECCALC; | ||
| 199 | + | ||
| 200 | + __aicore__ inline | ||
| 201 | + LocalTensorBuffer() | ||
| 202 | + { | ||
| 203 | + tensor = AscendC::LocalTensor<uint8_t>(AscendC::TPosition::VECCALC, 0, Arch::AtlasA5::UB_SIZE); | ||
| 204 | + } | ||
| 205 | +}; | ||
| 206 | + | ||
| 207 | + | ||
| 208 | +/// Partial specialization for TPosition::A1 | ||
| 209 | +template <> | ||
| 210 | +struct LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::A1> : LocalTensorBufferBase { | ||
| 211 | +public: | ||
| 212 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::A1; | ||
| 213 | + | ||
| 214 | + __aicore__ inline | ||
| 215 | + LocalTensorBuffer() | ||
| 216 | + { | ||
| 217 | + AscendC::TBuf<AscendC::TPosition::A1> tbufA1; | ||
| 218 | + GetTPipePtr()->InitBuffer(tbufA1, Arch::AtlasA2::L1_SIZE); | ||
| 219 | + tensor = tbufA1.Get<uint8_t>(); | ||
| 220 | + } | ||
| 221 | +}; | ||
| 222 | + | ||
| 223 | +/////////////////////////////////////////////////////////// | ||
| 224 | + | ||
| 225 | +/// Partial specialization for TPosition::A2 | ||
| 226 | +template <> | ||
| 227 | +struct LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::A2> : LocalTensorBufferBase { | ||
| 228 | +public: | ||
| 229 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::A2; | ||
| 230 | + | ||
| 231 | + __aicore__ inline | ||
| 232 | + LocalTensorBuffer() | ||
| 233 | + { | ||
| 234 | + AscendC::TBuf<AscendC::TPosition::A2> tbufA2; | ||
| 235 | + GetTPipePtr()->InitBuffer(tbufA2, Arch::AtlasA2::L0A_SIZE); | ||
| 236 | + tensor = tbufA2.Get<uint8_t>(); | ||
| 237 | + } | ||
| 238 | +}; | ||
| 239 | + | ||
| 240 | +/////////////////////////////////////////////////////////// | ||
| 241 | + | ||
| 242 | +/// Partial specialization for TPosition::B1 | ||
| 243 | +template <> | ||
| 244 | +struct LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::B1> : LocalTensorBufferBase { | ||
| 245 | +public: | ||
| 246 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::B1; | ||
| 247 | + | ||
| 248 | + __aicore__ inline | ||
| 249 | + LocalTensorBuffer() | ||
| 250 | + { | ||
| 251 | + AscendC::TBuf<AscendC::TPosition::B1> tbufB1; | ||
| 252 | + GetTPipePtr()->InitBuffer(tbufB1, Arch::AtlasA2::L1_SIZE); | ||
| 253 | + tensor = tbufB1.Get<uint8_t>(); | ||
| 254 | + } | ||
| 255 | +}; | ||
| 256 | + | ||
| 257 | +/////////////////////////////////////////////////////////// | ||
| 258 | + | ||
| 259 | +/// Partial specialization for AtlasA2, TPosition::B2 | ||
| 260 | +template <> | ||
| 261 | +struct LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::B2> : LocalTensorBufferBase { | ||
| 262 | +public: | ||
| 263 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::B2; | ||
| 264 | + | ||
| 265 | + __aicore__ inline | ||
| 266 | + LocalTensorBuffer() | ||
| 267 | + { | ||
| 268 | + AscendC::TBuf<AscendC::TPosition::B2> tbufB2; | ||
| 269 | + GetTPipePtr()->InitBuffer(tbufB2, Arch::AtlasA2::L0B_SIZE); | ||
| 270 | + tensor = tbufB2.Get<uint8_t>(); | ||
| 271 | + } | ||
| 272 | +}; | ||
| 273 | + | ||
| 274 | +/////////////////////////////////////////////////////////// | ||
| 275 | + | ||
| 276 | +/// Partial specialization for AtlasA2, TPosition::C1 | ||
| 277 | +template <> | ||
| 278 | +struct LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::C1> : LocalTensorBufferBase { | ||
| 279 | +public: | ||
| 280 | + using ArchTag = Arch::AtlasA2; | ||
| 281 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::C1; | ||
| 282 | + | ||
| 283 | + __aicore__ inline | ||
| 284 | + LocalTensorBuffer() | ||
| 285 | + { | ||
| 286 | + AscendC::TBuf<AscendC::TPosition::C1> tbufC1; | ||
| 287 | + GetTPipePtr()->InitBuffer(tbufC1, Arch::AtlasA2::L1_SIZE); | ||
| 288 | + tensor = tbufC1.Get<uint8_t>(); | ||
| 289 | + } | ||
| 290 | +}; | ||
| 291 | + | ||
| 292 | +/////////////////////////////////////////////////////////// | ||
| 293 | + | ||
| 294 | +/// Partial specialization for AtlasA2, TPosition::C2 | ||
| 295 | +template <> | ||
| 296 | +struct LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::C2> : LocalTensorBufferBase { | ||
| 297 | +public: | ||
| 298 | + using ArchTag = Arch::AtlasA2; | ||
| 299 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::C2; | ||
| 300 | + | ||
| 301 | + __aicore__ inline | ||
| 302 | + LocalTensorBuffer() | ||
| 303 | + { | ||
| 304 | + AscendC::TBuf<AscendC::TPosition::C2> tbufC2; | ||
| 305 | + GetTPipePtr()->InitBuffer(tbufC2, Arch::AtlasA2::BIAS_SIZE); | ||
| 306 | + tensor = tbufC2.Get<uint8_t>(); | ||
| 307 | + } | ||
| 308 | +}; | ||
| 309 | + | ||
| 310 | +/////////////////////////////////////////////////////////// | ||
| 311 | + | ||
| 312 | +/// Partial specialization for TPosition::CO1 | ||
| 313 | +template <> | ||
| 314 | +struct LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::CO1> : LocalTensorBufferBase { | ||
| 315 | +public: | ||
| 316 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::CO1; | ||
| 317 | + | ||
| 318 | + __aicore__ inline | ||
| 319 | + LocalTensorBuffer() | ||
| 320 | + { | ||
| 321 | + AscendC::TBuf<AscendC::TPosition::CO1> tbufCO1; | ||
| 322 | + GetTPipePtr()->InitBuffer(tbufCO1, Arch::AtlasA2::L0C_SIZE); | ||
| 323 | + tensor = tbufCO1.Get<uint8_t>(); | ||
| 324 | + } | ||
| 325 | +}; | ||
| 326 | + | ||
| 327 | +/// Partial specialization for TPosition::VECCALC | ||
| 328 | +template <> | ||
| 329 | +struct LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::VECCALC> : LocalTensorBufferBase { | ||
| 330 | +public: | ||
| 331 | + static constexpr AscendC::TPosition Position = AscendC::TPosition::VECCALC; | ||
| 332 | + | ||
| 333 | + __aicore__ inline | ||
| 334 | + LocalTensorBuffer() | ||
| 335 | + { | ||
| 336 | + AscendC::TBuf<AscendC::TPosition::VECCALC> tbufVECCALC; | ||
| 337 | + GetTPipePtr()->InitBuffer(tbufVECCALC, Arch::AtlasA2::UB_SIZE); | ||
| 338 | + tensor = tbufVECCALC.Get<uint8_t>(); | ||
| 339 | + } | ||
| 340 | +}; | ||
| 341 | +} // namespace NpuArch::Arch | ||
| 342 | + | ||
| 343 | + | ||
| @@ -0,0 +1,69 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace NpuArch::Arch | ||
| 18 | +{ | ||
| 19 | + | ||
| 20 | +template<class ArchTag> | ||
| 21 | +struct Resource | ||
| 22 | +{}; | ||
| 23 | + | ||
| 24 | +template<> | ||
| 25 | +struct Resource<Arch::AtlasA5> { | ||
| 26 | +public: | ||
| 27 | + LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::A1> l1Buf; | ||
| 28 | + LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::A2> l0ABuf; | ||
| 29 | + LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::B2> l0BBuf; | ||
| 30 | + LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::C2> btBuf; | ||
| 31 | + LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::CO1> l0CBuf; | ||
| 32 | + LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::VECCALC> ubBuf; | ||
| 33 | + LocalTensorBuffer<Arch::AtlasA5, AscendC::TPosition::C2PIPE2GM> fpBuf; | ||
| 34 | + | ||
| 35 | + __aicore__ inline | ||
| 36 | + Resource() | ||
| 37 | + { | ||
| 38 | + AscendC::InitSocState(); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + __aicore__ inline | ||
| 42 | + ~Resource() | ||
| 43 | + { | ||
| 44 | + AscendC::InitSocState(); | ||
| 45 | + } | ||
| 46 | +}; | ||
| 47 | + | ||
| 48 | +template<> | ||
| 49 | +struct Resource<Arch::AtlasA2> { | ||
| 50 | +public: | ||
| 51 | + AscendC::TPipe pipe; | ||
| 52 | + | ||
| 53 | + LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::A1> l1Buf; | ||
| 54 | + LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::A2> l0ABuf; | ||
| 55 | + LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::B2> l0BBuf; | ||
| 56 | + LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::C2> btBuf; | ||
| 57 | + LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::CO1> l0CBuf; | ||
| 58 | + LocalTensorBuffer<Arch::AtlasA2, AscendC::TPosition::VECCALC> ubBuf; | ||
| 59 | + | ||
| 60 | + __aicore__ inline | ||
| 61 | + Resource() | ||
| 62 | + { | ||
| 63 | + pipe.Destroy(); | ||
| 64 | + } | ||
| 65 | +}; | ||
| 66 | + | ||
| 67 | +} // namespace NpuArch::Arch | ||
| 68 | + | ||
| 69 | + | ||
| @@ -0,0 +1,59 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file base_defs.hpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + do { AscendC::printf("line %d, tensor: %s\n", __LINE__, #mmResUb); \ | ||
| 30 | + uint32_t array_ ## __LINE__[] = {static_cast<uint32_t>(m), static_cast<uint32_t>(n)}; \ | ||
| 31 | + AscendC::DumpTensor(mmResUb, 2, (m)*(n)); \ | ||
| 32 | + } while(0) | ||
| 33 | + | ||
| 34 | + | ||
| 35 | +namespace NpuArch { | ||
| 36 | + | ||
| 37 | +constexpr uint32_t BYTE_PER_C0 = 32; | ||
| 38 | +constexpr uint32_t BYTE_PER_C2 = 64; | ||
| 39 | +constexpr uint32_t C0_NUM_PER_FRACTAL = 16; | ||
| 40 | +constexpr uint32_t BYTE_PER_FRACTAL = BYTE_PER_C0 * C0_NUM_PER_FRACTAL; | ||
| 41 | + | ||
| 42 | +constexpr uint32_t BYTE_PER_BLK = 32; | ||
| 43 | +constexpr uint32_t BLK_NUM_PER_VECTOR_FRACTAL = 8; | ||
| 44 | +constexpr uint32_t BYTE_PER_VECTOR_FRACTAL = BYTE_PER_BLK * BLK_NUM_PER_VECTOR_FRACTAL; | ||
| 45 | + | ||
| 46 | +constexpr uint64_t L2_OFFSET = 0; | ||
| 47 | +constexpr uint32_t STRIDE_LIMIT = 65536; | ||
| 48 | + | ||
| 49 | +constexpr uint32_t BYTE_PER_BLK_FP = 128; /// datablock size of A1->C2PiPE2GM | ||
| 50 | + | ||
| 51 | +constexpr uint32_t MX_SCALE_COPY_GROUP_NUM = 2; | ||
| 52 | +constexpr uint32_t MX_SCALE_GROUP_NUM = 32; | ||
| 53 | +constexpr uint32_t MX_BASEK_FACTOR = 64; | ||
| 54 | + | ||
| 55 | +class EmptyClass {}; | ||
| 56 | + | ||
| 57 | +} // namespace NpuArch | ||
| 58 | + | ||
| 59 | + | ||
| @@ -0,0 +1,442 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file coord.hpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace NpuArch { | ||
| 22 | + | ||
| 23 | +/// Statically-sized array specifying Coords within a tensor | ||
| 24 | +template < | ||
| 25 | + int RANK_, ///< Logical rank of coordinate | ||
| 26 | + class Index_ = uint32_t, ///< Index type used for each dimension | ||
| 27 | + class LongIndex_ = int64_t ///< Long index type used for linear offsets | ||
| 28 | +> | ||
| 29 | +struct Coord { | ||
| 30 | +public: | ||
| 31 | + // Number of elements in Coord | ||
| 32 | + static const int RANK = RANK_; | ||
| 33 | + | ||
| 34 | + // Index typen used to store elements | ||
| 35 | + using Index = Index_; | ||
| 36 | + | ||
| 37 | + // Type used to represent linear offsets | ||
| 38 | + using LongIndex = LongIndex_; | ||
| 39 | + | ||
| 40 | + // Default ctor initializes uniformly | ||
| 41 | + HOST_DEVICE constexpr | ||
| 42 | + explicit Coord(Index value = Index(0)) | ||
| 43 | + { | ||
| 44 | + for (int i = 0; i < RANK; ++i) { | ||
| 45 | + idx[i] = value; | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + // Constructs from an array of integers | ||
| 50 | + HOST_DEVICE constexpr | ||
| 51 | + Coord(Index const (&idx_)[RANK]) | ||
| 52 | + { | ||
| 53 | + for (int i = 0; i < RANK; ++i) { | ||
| 54 | + idx[i] = idx_[i]; | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + HOST_DEVICE | ||
| 59 | + int Argmin() const | ||
| 60 | + { | ||
| 61 | + return ArgminImpl<1>(0); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + // Returns the index of the dimension with greatest value | ||
| 65 | + HOST_DEVICE | ||
| 66 | + int Argmax() const | ||
| 67 | + { | ||
| 68 | + return ArgmaxImpl<1>(0); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + // Returns true if Coord is non-zero | ||
| 72 | + HOST_DEVICE | ||
| 73 | + explicit operator bool() const | ||
| 74 | + { | ||
| 75 | + return AnyImpl<0>(); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + // Return true if Coord is uniformly zero. | ||
| 79 | + HOST_DEVICE | ||
| 80 | + bool operator!() const | ||
| 81 | + { | ||
| 82 | + return !AnyImpl<0>(); | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + // Element-wise addition | ||
| 86 | + HOST_DEVICE | ||
| 87 | + Coord operator+(Coord const &b) const | ||
| 88 | + { | ||
| 89 | + Coord c; | ||
| 90 | + AddCoordImpl<0>(c, b); | ||
| 91 | + return c; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + // Add a scalar to each element | ||
| 95 | + HOST_DEVICE | ||
| 96 | + Coord operator+(const Index val) const | ||
| 97 | + { | ||
| 98 | + Coord c; | ||
| 99 | + AddScalarImpl<0>(c, val); | ||
| 100 | + return c; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + // Element-wise subtraction | ||
| 104 | + HOST_DEVICE | ||
| 105 | + Coord operator-(Coord const &b) const | ||
| 106 | + { | ||
| 107 | + Coord c; | ||
| 108 | + SubCoordImpl<0>(c, b); | ||
| 109 | + return c; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + // Subtract a scalar from each element | ||
| 113 | + HOST_DEVICE | ||
| 114 | + Coord operator-(Index const val) const | ||
| 115 | + { | ||
| 116 | + Coord c; | ||
| 117 | + SubScalarImpl<0>(c, val); | ||
| 118 | + return c; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + // Element-wise multiply | ||
| 122 | + HOST_DEVICE | ||
| 123 | + Coord operator*(Coord const &b) const | ||
| 124 | + { | ||
| 125 | + Coord c; | ||
| 126 | + MulCoordImpl<0>(c, b); | ||
| 127 | + return c; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + // Element-wise division | ||
| 131 | + HOST_DEVICE | ||
| 132 | + Coord operator/(Coord const &b) const | ||
| 133 | + { | ||
| 134 | + Coord c; | ||
| 135 | + DivCoordImpl<0>(c, b); | ||
| 136 | + return c; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + // Element-wise mod | ||
| 140 | + HOST_DEVICE | ||
| 141 | + Coord operator%(Coord const &b) const | ||
| 142 | + { | ||
| 143 | + Coord c; | ||
| 144 | + ModCoordImpl<0>(c, b); | ||
| 145 | + return c; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + // In-place addition | ||
| 149 | + HOST_DEVICE | ||
| 150 | + Coord &operator+=(Coord const &b) | ||
| 151 | + { | ||
| 152 | + PlusEqualImpl<0>(b); | ||
| 153 | + return *this; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + // In-place equal | ||
| 157 | + HOST_DEVICE | ||
| 158 | + bool operator==(Coord const &b) const | ||
| 159 | + { | ||
| 160 | + return EqualCoordImpl<0>(b); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + // In-place equal | ||
| 164 | + HOST_DEVICE | ||
| 165 | + bool operator==(Index const val) const | ||
| 166 | + { | ||
| 167 | + return EqualScalarImpl<0>(val); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + // Member acces operator | ||
| 171 | + HOST_DEVICE | ||
| 172 | + Index &operator[](int dim) | ||
| 173 | + { | ||
| 174 | + return idx[dim]; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + // Member access operator | ||
| 178 | + HOST_DEVICE | ||
| 179 | + Index const &operator[](int dim) const | ||
| 180 | + { | ||
| 181 | + return idx[dim]; | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + // Gets the index of a given Coord element | ||
| 185 | + template <int DIM> | ||
| 186 | + HOST_DEVICE | ||
| 187 | + Index &At() | ||
| 188 | + { | ||
| 189 | + return idx[DIM]; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + // Access via index; may limit unrolling potential | ||
| 193 | + HOST_DEVICE | ||
| 194 | + Index &At(int dim) | ||
| 195 | + { | ||
| 196 | + return idx[dim]; | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + // Gets the index of a given Coord element | ||
| 200 | + template <int DIM> | ||
| 201 | + HOST_DEVICE | ||
| 202 | + Index const &At() const | ||
| 203 | + { | ||
| 204 | + return idx[DIM]; | ||
| 205 | + } | ||
| 206 | + | ||
| 207 | + // Access via index; may limit unrolling potential | ||
| 208 | + HOST_DEVICE | ||
| 209 | + Index const &At(int dim) const | ||
| 210 | + { | ||
| 211 | + return idx[dim]; | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + template <int... Is> | ||
| 215 | + HOST_DEVICE | ||
| 216 | + auto GetCoordByAxis() const | ||
| 217 | + { | ||
| 218 | + Index idx_[sizeof...(Is)]{idx[Is]...}; | ||
| 219 | + return Coord<sizeof...(Is), Index, LongIndex>{idx_}; | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + HOST_DEVICE | ||
| 223 | + static Coord Min(Coord const &a, Coord const &b) | ||
| 224 | + { | ||
| 225 | + Coord res; | ||
| 226 | + for (int i = 0; i < RANK; ++i) { | ||
| 227 | + res[i] = a[i] < b[i] ? a[i] : b[i]; | ||
| 228 | + } | ||
| 229 | + return res; | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | +private: | ||
| 233 | + template <int N> | ||
| 234 | + HOST_DEVICE | ||
| 235 | + int ArgminImpl(int i) const | ||
| 236 | + { | ||
| 237 | + if constexpr (N == RANK) { | ||
| 238 | + return i; | ||
| 239 | + } | ||
| 240 | + else { | ||
| 241 | + return ArgminImpl<N + 1>(idx[N] < idx[i] ? N : i); | ||
| 242 | + } | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + template <int N> | ||
| 246 | + HOST_DEVICE | ||
| 247 | + int ArgmaxImpl(int i) const | ||
| 248 | + { | ||
| 249 | + if constexpr (N == RANK) { | ||
| 250 | + return i; | ||
| 251 | + } | ||
| 252 | + else { | ||
| 253 | + return ArgmaxImpl<N + 1>(idx[N] > idx[i] ? N : i); | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + template <int N> | ||
| 258 | + HOST_DEVICE | ||
| 259 | + bool AnyImpl() const | ||
| 260 | + { | ||
| 261 | + if constexpr (N == RANK) { | ||
| 262 | + return false; | ||
| 263 | + } | ||
| 264 | + else { | ||
| 265 | + return idx[N] || AnyImpl<N + 1>(); | ||
| 266 | + } | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + template <int N> | ||
| 270 | + HOST_DEVICE | ||
| 271 | + void AddCoordImpl(Coord &c, Coord const &b) const | ||
| 272 | + { | ||
| 273 | + if constexpr (N < RANK) { | ||
| 274 | + c.idx[N] = idx[N] + b.idx[N]; | ||
| 275 | + AddCoordImpl<N + 1>(c, b); | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + template <int N> | ||
| 280 | + HOST_DEVICE | ||
| 281 | + void AddScalarImpl(Coord &c, Index const val) const | ||
| 282 | + { | ||
| 283 | + if constexpr (N < RANK) { | ||
| 284 | + c.idx[N] = idx[N] + val; | ||
| 285 | + AddScalarImpl<N + 1>(c, val); | ||
| 286 | + } | ||
| 287 | + } | ||
| 288 | + | ||
| 289 | + template <int N> | ||
| 290 | + HOST_DEVICE | ||
| 291 | + void SubCoordImpl(Coord &c, Coord const &b) const | ||
| 292 | + { | ||
| 293 | + if constexpr (N < RANK) { | ||
| 294 | + c.idx[N] = idx[N] - b.idx[N]; | ||
| 295 | + SubCoordImpl<N + 1>(c, b); | ||
| 296 | + } | ||
| 297 | + } | ||
| 298 | + | ||
| 299 | + template <int N> | ||
| 300 | + HOST_DEVICE | ||
| 301 | + void SubScalarImpl(Coord &c, Index const val) const | ||
| 302 | + { | ||
| 303 | + if constexpr (N < RANK) { | ||
| 304 | + c.idx[N] = idx[N] - val; | ||
| 305 | + SubScalarImpl<N + 1>(c, val); | ||
| 306 | + } | ||
| 307 | + } | ||
| 308 | + | ||
| 309 | + template <int N> | ||
| 310 | + HOST_DEVICE | ||
| 311 | + void MulCoordImpl(Coord &c, Coord const &b) const | ||
| 312 | + { | ||
| 313 | + if constexpr (N < RANK) { | ||
| 314 | + c.idx[N] = idx[N] * b.idx[N]; | ||
| 315 | + MulCoordImpl<N + 1>(c, b); | ||
| 316 | + } | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + template <int N> | ||
| 320 | + HOST_DEVICE | ||
| 321 | + void DivCoordImpl(Coord &c, Coord const &b) const | ||
| 322 | + { | ||
| 323 | + if constexpr (N < RANK) { | ||
| 324 | + c.idx[N] = idx[N] / b.idx[N]; | ||
| 325 | + DivCoordImpl<N + 1>(c, b); | ||
| 326 | + } | ||
| 327 | + } | ||
| 328 | + | ||
| 329 | + template <int N> | ||
| 330 | + HOST_DEVICE | ||
| 331 | + void ModCoordImpl(Coord &c, Coord const &b) const | ||
| 332 | + { | ||
| 333 | + if constexpr (N < RANK) { | ||
| 334 | + c.idx[N] = idx[N] % b.idx[N]; | ||
| 335 | + ModCoordImpl<N + 1>(c, b); | ||
| 336 | + } | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + template <int N> | ||
| 340 | + HOST_DEVICE | ||
| 341 | + void PlusEqualImpl(Coord const &b) | ||
| 342 | + { | ||
| 343 | + if constexpr (N < RANK) { | ||
| 344 | + idx[N] += b.idx[N]; | ||
| 345 | + PlusEqualImpl<N + 1>(b); | ||
| 346 | + } | ||
| 347 | + } | ||
| 348 | + | ||
| 349 | + template <int N> | ||
| 350 | + HOST_DEVICE | ||
| 351 | + bool EqualCoordImpl(Coord const &b) const | ||
| 352 | + { | ||
| 353 | + if constexpr (N == RANK) { | ||
| 354 | + return true; | ||
| 355 | + } | ||
| 356 | + else { | ||
| 357 | + return idx[N] == b.idx[N] && EqualCoordImpl<N + 1>(b); | ||
| 358 | + } | ||
| 359 | + } | ||
| 360 | + | ||
| 361 | + template <int N> | ||
| 362 | + HOST_DEVICE | ||
| 363 | + bool EqualScalarImpl(Index const val) const | ||
| 364 | + { | ||
| 365 | + if constexpr (N == RANK) { | ||
| 366 | + return true; | ||
| 367 | + } | ||
| 368 | + else { | ||
| 369 | + return idx[N] == val && EqualScalarImpl<N + 1>(val); | ||
| 370 | + } | ||
| 371 | + } | ||
| 372 | + | ||
| 373 | + // Indices | ||
| 374 | + Index idx[RANK]; | ||
| 375 | +}; | ||
| 376 | + | ||
| 377 | +// Helper to make a 1-element coordinate | ||
| 378 | +template <class T> | ||
| 379 | +HOST_DEVICE constexpr | ||
| 380 | +Coord<1, T> MakeCoord(T dim0) | ||
| 381 | +{ | ||
| 382 | + T values[1] = {dim0}; | ||
| 383 | + return Coord<1, T>(values); | ||
| 384 | +} | ||
| 385 | + | ||
| 386 | +/// Helper to make a 2-element coordinate | ||
| 387 | +template <class T> | ||
| 388 | +HOST_DEVICE constexpr | ||
| 389 | +Coord<2, T> MakeCoord(T dim0, T dim1) | ||
| 390 | +{ | ||
| 391 | + T values[2] = {dim0, dim1}; | ||
| 392 | + return Coord<2, T>(values); | ||
| 393 | +} | ||
| 394 | + | ||
| 395 | +/// Helper to make a 3-element coordinate | ||
| 396 | +template <class T> | ||
| 397 | +HOST_DEVICE constexpr | ||
| 398 | +Coord<3, T> MakeCoord(T dim0, T dim1, T dim2) | ||
| 399 | +{ | ||
| 400 | + T values[3] = {dim0, dim1, dim2}; | ||
| 401 | + return Coord<3, T>(values); | ||
| 402 | +} | ||
| 403 | + | ||
| 404 | +/// Helper to make a 4-element coordinate | ||
| 405 | +template <class T> | ||
| 406 | +HOST_DEVICE constexpr | ||
| 407 | +Coord<4, T> MakeCoord(T dim0, T dim1, T dim2, T dim3) | ||
| 408 | +{ | ||
| 409 | + T values[4] = {dim0, dim1, dim2, dim3}; | ||
| 410 | + return Coord<4, T>(values); | ||
| 411 | +} | ||
| 412 | + | ||
| 413 | +/// Helper to make a 5-element coordinate | ||
| 414 | +template <class T> | ||
| 415 | +HOST_DEVICE constexpr | ||
| 416 | +Coord<5, T> MakeCoord(T dim0, T dim1, T dim2, T dim3, T dim4) | ||
| 417 | +{ | ||
| 418 | + T values[5] = {dim0, dim1, dim2, dim3, dim4}; | ||
| 419 | + return Coord<5, T>(values); | ||
| 420 | +} | ||
| 421 | + | ||
| 422 | +/// Helper to make a 6-element coordinate | ||
| 423 | +template <class T> | ||
| 424 | +HOST_DEVICE constexpr | ||
| 425 | +Coord<6, T> MakeCoord(T dim0, T dim1, T dim2, T dim3, T dim4, T dim5) | ||
| 426 | +{ | ||
| 427 | + T values[6] = {dim0, dim1, dim2, dim3, dim4, dim5}; | ||
| 428 | + return Coord<6, T>(values); | ||
| 429 | +} | ||
| 430 | + | ||
| 431 | +/// Helper to make a 7-element coordinate | ||
| 432 | +template <class T> | ||
| 433 | +HOST_DEVICE constexpr | ||
| 434 | +Coord<7, T> MakeCoord(T dim0, T dim1, T dim2, T dim3, T dim4, T dim5, T dim6) | ||
| 435 | +{ | ||
| 436 | + T values[7] = {dim0, dim1, dim2, dim3, dim4, dim5, dim6}; | ||
| 437 | + return Coord<7, T>(values); | ||
| 438 | +} | ||
| 439 | + | ||
| 440 | +} // namespace NpuArch | ||
| 441 | + | ||
| 442 | + | ||
| @@ -0,0 +1,129 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +template <uint32_t ALIGN, typename T> | ||
| 20 | +HOST_DEVICE | ||
| 21 | +constexpr T RoundDown(const T val) | ||
| 22 | +{ | ||
| 23 | + static_assert(ALIGN != 0U, "ALIGN must not be 0"); | ||
| 24 | + return val / ALIGN * ALIGN; | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +template <class T, class U> | ||
| 28 | +HOST_DEVICE | ||
| 29 | +constexpr auto RoundDown(T const &val, U const &align) | ||
| 30 | +{ | ||
| 31 | + if constexpr (tla::is_static<T>::value && tla::is_static<U>::value) { // Int, Int | ||
| 32 | + constexpr uint32_t res = T::value / U::value * U::value; | ||
| 33 | + return tla::Int<res>{}; | ||
| 34 | + } else if constexpr (tla::is_static<T>::value) { // Int, int | ||
| 35 | + return T::value / align * align; | ||
| 36 | + } else if constexpr (tla::is_static<U>::value) { // int, Int | ||
| 37 | + return val / U::value * U::value; | ||
| 38 | + } else { // int, int | ||
| 39 | + return val / align * align; | ||
| 40 | + } | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +template <uint32_t ALIGN, typename T = uint32_t> | ||
| 44 | +HOST_DEVICE | ||
| 45 | +constexpr T RoundUp(const T val) | ||
| 46 | +{ | ||
| 47 | + static_assert(ALIGN != 0U, "ALIGN must not be 0"); | ||
| 48 | + T align = ALIGN; | ||
| 49 | + if (val + align - 1 < val) { | ||
| 50 | + return val; | ||
| 51 | + } | ||
| 52 | + return (val + align - 1) / align * align; | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +template <class T, class U> | ||
| 56 | +HOST_DEVICE | ||
| 57 | +constexpr auto RoundUp(T const &val, U const &align) | ||
| 58 | +{ | ||
| 59 | + if constexpr (tla::is_static<T>::value && tla::is_static<U>::value) { // Int, Int | ||
| 60 | + constexpr uint32_t res = (T::value + U::value - 1) / U::value * U::value; | ||
| 61 | + return tla::Int<res>{}; | ||
| 62 | + } else if constexpr (tla::is_static<T>::value) { // Int, int | ||
| 63 | + return (T::value + align - 1) / align * align; | ||
| 64 | + } else if constexpr (tla::is_static<U>::value) { // int, Int | ||
| 65 | + return (val + U::value - 1) / U::value * U::value; | ||
| 66 | + } else { // int, int | ||
| 67 | + return (val + align - 1) / align * align; | ||
| 68 | + } | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +template <uint32_t DIVISOR, typename T = uint32_t> | ||
| 72 | +HOST_DEVICE | ||
| 73 | +constexpr T CeilDiv(const T dividend) | ||
| 74 | +{ | ||
| 75 | + static_assert(DIVISOR != 0U, "DIVISOR must not be 0"); | ||
| 76 | + T divisor = DIVISOR; | ||
| 77 | + if (dividend + divisor - 1 < dividend) { | ||
| 78 | + return dividend; | ||
| 79 | + } | ||
| 80 | + return (dividend + divisor - 1) / divisor; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +template <class T> | ||
| 84 | +HOST_DEVICE | ||
| 85 | +constexpr T CeilDiv(const T dividend, const T divisor) | ||
| 86 | +{ | ||
| 87 | + if (divisor == 0 || dividend + divisor - 1 < dividend) { | ||
| 88 | + return std::numeric_limits<T>::max(); | ||
| 89 | + } | ||
| 90 | + return (dividend + divisor - 1) / divisor; | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +template <class T, class U> | ||
| 94 | +HOST_DEVICE | ||
| 95 | +constexpr auto CeilDiv(T const ÷nd, U const &divisor) | ||
| 96 | +{ | ||
| 97 | + if constexpr (tla::is_static<T>::value && tla::is_static<U>::value) { // Int, Int | ||
| 98 | + constexpr uint32_t res = (T::value + U::value - 1) / U::value; | ||
| 99 | + return tla::Int<res>{}; | ||
| 100 | + } else if constexpr (tla::is_static<T>::value) { // Int, int | ||
| 101 | + return (T::value + divisor - 1) / divisor; | ||
| 102 | + } else if constexpr (tla::is_static<U>::value) { // int, Int | ||
| 103 | + return (dividend + U::value - 1) / U::value; | ||
| 104 | + } else { // int, int | ||
| 105 | + return (dividend + divisor - 1) / divisor; | ||
| 106 | + } | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | +template <class T, class U> | ||
| 110 | +HOST_DEVICE | ||
| 111 | +constexpr auto Max(T const &a, U const &b) { | ||
| 112 | + if (a > b) { | ||
| 113 | + return a; | ||
| 114 | + } else { | ||
| 115 | + return b; | ||
| 116 | + } | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +template <class T, class U> | ||
| 120 | +HOST_DEVICE | ||
| 121 | +constexpr auto Min(T const &a, U const &b) { | ||
| 122 | + if (a < b) { | ||
| 123 | + return a; | ||
| 124 | + } else { | ||
| 125 | + return b; | ||
| 126 | + } | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | + | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +template <bool VALUE, class... Args> | ||
| 15 | +constexpr bool DEPENDENT_BOOL_VALUE = VALUE; | ||
| 16 | + | ||
| 17 | +template <class... Args> | ||
| 18 | +constexpr bool DEPENDENT_FALSE = DEPENDENT_BOOL_VALUE<false, Args...>; | ||
| 19 | + | ||
| 20 | + | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| @@ -0,0 +1,106 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +//////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 18 | + | ||
| 19 | +namespace NpuArch::detail { | ||
| 20 | +//////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 21 | +// For each NpuArch::layout, provides its corresponding tla layout types | ||
| 22 | +template <class Element, class LayoutTag> | ||
| 23 | +struct TagToLayout { | ||
| 24 | + using type = LayoutTag; | ||
| 25 | +}; | ||
| 26 | + | ||
| 27 | +template <class Element> | ||
| 28 | +struct TagToLayout<Element, layout::RowMajor> { | ||
| 29 | + using type = tla::Layout<tla::Shape<uint32_t, uint32_t>, tla::Stride<int64_t, tla::Int<1>>>; | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +template <class Element> | ||
| 33 | +struct TagToLayout<Element, layout::ColumnMajor> { | ||
| 34 | + using type = tla::Layout<tla::Shape<uint32_t, uint32_t>, tla::Stride<tla::Int<1>, int64_t>>; | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +template <class Element> | ||
| 38 | +struct TagToLayout<Element, layout::VectorLayout> { | ||
| 39 | + using type = tla::Layout<tla::Shape<uint32_t>, tla::Stride<tla::Int<1>>>; | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +template <class Element> | ||
| 43 | +struct TagToLayout<Element, layout::zN> { | ||
| 44 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 45 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 46 | + using type = tla::Layout< | ||
| 47 | + tla::Shape<tla::Shape<tla::Int<C0_NUM_PER_FRACTAL>, uint32_t>, tla::Shape<tla::Int<ELE_NUM_PER_C0>, uint32_t>>, | ||
| 48 | + tla::Stride<tla::Stride<tla::Int<ELE_NUM_PER_C0>, tla::Int<ELE_NUM_PER_FRACTAL>>, | ||
| 49 | + tla::Stride<tla::Int<1>, int64_t>>>; | ||
| 50 | +}; | ||
| 51 | + | ||
| 52 | +template <class Element> | ||
| 53 | +struct TagToLayout<Element, layout::zZ> { | ||
| 54 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 55 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 56 | + using type = tla::Layout< | ||
| 57 | + tla::Shape<tla::Shape<tla::Int<C0_NUM_PER_FRACTAL>, uint32_t>, tla::Shape<tla::Int<ELE_NUM_PER_C0>, uint32_t>>, | ||
| 58 | + tla::Stride<tla::Stride<tla::Int<ELE_NUM_PER_C0>, int64_t>, | ||
| 59 | + tla::Stride<tla::Int<1>, tla::Int<ELE_NUM_PER_FRACTAL>>>>; | ||
| 60 | +}; | ||
| 61 | + | ||
| 62 | +template <class Element> | ||
| 63 | +struct TagToLayout<Element, layout::nZ> { | ||
| 64 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 65 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 66 | + using type = tla::Layout< | ||
| 67 | + tla::Shape<tla::Shape<tla::Int<ELE_NUM_PER_C0>, uint32_t>, tla::Shape<tla::Int<C0_NUM_PER_FRACTAL>, uint32_t>>, | ||
| 68 | + tla::Stride<tla::Stride<tla::Int<1>, int64_t>, | ||
| 69 | + tla::Stride<tla::Int<ELE_NUM_PER_C0>, tla::Int<ELE_NUM_PER_FRACTAL>>>>; | ||
| 70 | +}; | ||
| 71 | + | ||
| 72 | +template <> | ||
| 73 | +struct TagToLayout<AscendC::fp8_e8m0_t, layout::zZ> { | ||
| 74 | + static constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 75 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = 32; | ||
| 76 | + using type = tla::Layout< | ||
| 77 | + tla::Shape<tla::Shape<tla::Int<C0_NUM_PER_FRACTAL>, uint32_t>, tla::Shape<tla::Int<ELE_NUM_PER_C0>, uint32_t>>, | ||
| 78 | + tla::Stride<tla::Stride<tla::Int<ELE_NUM_PER_C0>, int64_t>, | ||
| 79 | + tla::Stride<tla::Int<1>, tla::Int<ELE_NUM_PER_FRACTAL>>>>; | ||
| 80 | +}; | ||
| 81 | + | ||
| 82 | +template <> | ||
| 83 | +struct TagToLayout<AscendC::fp8_e8m0_t, layout::nN> { | ||
| 84 | + static constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 85 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = 32; | ||
| 86 | + using type = tla::Layout< | ||
| 87 | + tla::Shape<tla::Shape<tla::Int<ELE_NUM_PER_C0>, uint32_t>, tla::Shape<tla::Int<C0_NUM_PER_FRACTAL>, uint32_t>>, | ||
| 88 | + tla::Stride<tla::Stride<tla::Int<1>, tla::Int<ELE_NUM_PER_FRACTAL>>, | ||
| 89 | + tla::Stride<tla::Int<ELE_NUM_PER_C0>, int64_t>>>; | ||
| 90 | +}; | ||
| 91 | + | ||
| 92 | +// Convenience aliases | ||
| 93 | +template <class Element, class LayoutTag> | ||
| 94 | +using TagToLayout_t = typename TagToLayout<Element, LayoutTag>::type; | ||
| 95 | + | ||
| 96 | +constexpr uint32_t ELE_NUM_PER_FRACTAL_L0C = 256; | ||
| 97 | +using LayoutL0C = tla::Layout< | ||
| 98 | + tla::Shape<tla::Shape<tla::Int<C0_NUM_PER_FRACTAL>, uint32_t>, tla::Shape<tla::Int<C0_NUM_PER_FRACTAL>, uint32_t>>, | ||
| 99 | + tla::Stride<tla::Stride<tla::Int<C0_NUM_PER_FRACTAL>, tla::Int<ELE_NUM_PER_FRACTAL_L0C>>, | ||
| 100 | + tla::Stride<tla::Int<1>, int64_t>>>; | ||
| 101 | + | ||
| 102 | +//////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 103 | + | ||
| 104 | +} // namespace NpuArch::detail | ||
| 105 | + | ||
| 106 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/epilogue/block/block_epilogue.hpp+39-0
| @@ -0,0 +1,39 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace NpuArch::Epilogue::Block { | ||
| 17 | + | ||
| 18 | +template < | ||
| 19 | + class DispatchPolicy, | ||
| 20 | + class... Args | ||
| 21 | +> | ||
| 22 | +class BlockEpilogue { | ||
| 23 | + static_assert(DEPENDENT_FALSE<DispatchPolicy>, "Could not find an epilogue specialization"); | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +} // namespace NpuArch::Epilogue::Block | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| @@ -0,0 +1,199 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace NpuArch::Epilogue::Block { | ||
| 21 | + | ||
| 22 | +template < | ||
| 23 | + class ElementSparseMask_, | ||
| 24 | + class ElementSparseIdx_, | ||
| 25 | + class ElementSparseCount_ | ||
| 26 | +> | ||
| 27 | +class BlockEpilogue < | ||
| 28 | + EpilogueBsaMask2Idx, | ||
| 29 | + ElementSparseMask_, | ||
| 30 | + ElementSparseIdx_, | ||
| 31 | + ElementSparseCount_> | ||
| 32 | +{ | ||
| 33 | +public: | ||
| 34 | + using DispatchPolicy = EpilogueBsaMask2Idx; | ||
| 35 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 36 | + using ElementSparseMask = ElementSparseMask_; | ||
| 37 | + using ElementSparseIdx = ElementSparseIdx_; | ||
| 38 | + using ElementSparseCount = ElementSparseCount_; | ||
| 39 | + | ||
| 40 | + static constexpr uint32_t IO_STAGES = DispatchPolicy::IO_STAGES; | ||
| 41 | + static constexpr uint32_t PRE_ROW_TILE = 128; | ||
| 42 | + static constexpr uint32_t PRE_COL_TILE = 64; | ||
| 43 | + static constexpr uint32_t PRE_ELEM_NUM_PER_LOOP = PRE_ROW_TILE * PRE_COL_TILE; | ||
| 44 | + | ||
| 45 | + __aicore__ inline | ||
| 46 | + BlockEpilogue(Arch::Resource<ArchTag> &resource) | ||
| 47 | + { | ||
| 48 | + constexpr uint32_t MASK_PAT_IN_UINT8 = 0; | ||
| 49 | + constexpr uint32_t MASK_PAT_IN_FP16 = 2 * PRE_ELEM_NUM_PER_LOOP; | ||
| 50 | + constexpr uint32_t MASK_PAT_IN_FP32 = 4 * PRE_ELEM_NUM_PER_LOOP; // 2(db)+2 | ||
| 51 | + constexpr uint32_t MASK_PAT_IN_BIT = 8 * PRE_ELEM_NUM_PER_LOOP; // 1+2+4 | ||
| 52 | + constexpr uint32_t MASK_IDX = 9 * PRE_ELEM_NUM_PER_LOOP; // 1+2+4+1 | ||
| 53 | + constexpr uint32_t RSVD_SPARSE_IDX = 13 * PRE_ELEM_NUM_PER_LOOP; // 1+2+4+1+4 | ||
| 54 | + constexpr uint32_t RSVD_SPARSE_COUNT = 21 * PRE_ELEM_NUM_PER_LOOP; // 1+2+4+1+4+8(db) | ||
| 55 | + | ||
| 56 | + for (uint32_t i = 0; i < IO_STAGES; i++) { | ||
| 57 | + maskPatUb8[i] = resource.ubBuf.template GetBufferByByte<ElementSparseMask>( | ||
| 58 | + MASK_PAT_IN_UINT8 + i * PRE_ELEM_NUM_PER_LOOP * sizeof(ElementSparseMask)); | ||
| 59 | + sparseIdxUb[i] = resource.ubBuf.template GetBufferByByte<ElementSparseIdx>( | ||
| 60 | + RSVD_SPARSE_IDX + i * PRE_ELEM_NUM_PER_LOOP * sizeof(ElementSparseIdx)); | ||
| 61 | + sparseCountUb[i] = resource.ubBuf.template GetBufferByByte<ElementSparseCount>( | ||
| 62 | + RSVD_SPARSE_COUNT + i * PRE_ROW_TILE * sizeof(ElementSparseCount)); | ||
| 63 | + } | ||
| 64 | + maskPatUb16 = resource.ubBuf.template GetBufferByByte<half>(MASK_PAT_IN_FP16); | ||
| 65 | + maskPatUb32 = resource.ubBuf.template GetBufferByByte<float>(MASK_PAT_IN_FP32); | ||
| 66 | + maskPatInBitUb8 = resource.ubBuf.template GetBufferByByte<uint8_t>(MASK_PAT_IN_BIT); | ||
| 67 | + maskPatInBitUb32 = resource.ubBuf.template GetBufferByByte<uint32_t>(MASK_PAT_IN_BIT); | ||
| 68 | + maskIdxUb = resource.ubBuf.template GetBufferByByte<ElementSparseIdx>(MASK_IDX); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + __aicore__ inline | ||
| 72 | + void operator()( | ||
| 73 | + AscendC::GlobalTensor<ElementSparseMask> gSparseMask, | ||
| 74 | + AscendC::GlobalTensor<ElementSparseIdx> gSparseIdx, | ||
| 75 | + AscendC::GlobalTensor<ElementSparseCount> gSparseCount, | ||
| 76 | + uint32_t totalRowNumBlockMask, | ||
| 77 | + uint32_t yBlockNumAligned, | ||
| 78 | + uint32_t avgRowPerSubCore, | ||
| 79 | + uint32_t preActiveSubCoreNum) | ||
| 80 | + { | ||
| 81 | + uint32_t subCoreIdx = AscendC::GetBlockIdx(); | ||
| 82 | + uint32_t curSubCoreRowOffset = subCoreIdx * avgRowPerSubCore; | ||
| 83 | + uint32_t actDealtRow = (subCoreIdx == preActiveSubCoreNum - 1) ? | ||
| 84 | + (totalRowNumBlockMask - curSubCoreRowOffset) : avgRowPerSubCore; | ||
| 85 | + | ||
| 86 | + if (subCoreIdx < preActiveSubCoreNum) { | ||
| 87 | + uint32_t rowLoop = CeilDiv(actDealtRow, PRE_ROW_TILE); | ||
| 88 | + uint32_t colLoop = CeilDiv(yBlockNumAligned, PRE_COL_TILE); | ||
| 89 | + uint32_t IdxPingPongFlag = 0; | ||
| 90 | + uint32_t CountPingPongFlag = 0; | ||
| 91 | + for (uint32_t i = 0; i < rowLoop; i++) { | ||
| 92 | + uint32_t curLoopRowOffset = i * PRE_ROW_TILE; | ||
| 93 | + uint32_t globalRowOffset = curSubCoreRowOffset + curLoopRowOffset; | ||
| 94 | + uint32_t actDealtRowCurLoop = (i == rowLoop - 1) ? (actDealtRow - curLoopRowOffset) : PRE_ROW_TILE; | ||
| 95 | + | ||
| 96 | + uint64_t rsvdCountPerRow[PRE_ROW_TILE] = {0}; | ||
| 97 | + uint64_t rsvdCountPerRowCurColLoop[PRE_ROW_TILE] = {0}; | ||
| 98 | + for (uint32_t j = 0; j < colLoop; j++) { | ||
| 99 | + uint32_t curLoopColOffset = j * PRE_COL_TILE; | ||
| 100 | + uint32_t actDealtColCurLoop = | ||
| 101 | + (j == colLoop - 1) ? (yBlockNumAligned - curLoopColOffset) : PRE_COL_TILE; | ||
| 102 | + uint32_t actDealtColCurLoop32 = CeilDiv(actDealtColCurLoop, 32) * 32; | ||
| 103 | + AscendC::CreateVecIndex( | ||
| 104 | + maskIdxUb, static_cast<int32_t>(curLoopColOffset), actDealtColCurLoop); | ||
| 105 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 106 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(IdxPingPongFlag); | ||
| 107 | + AscendC::DataCopyPad( | ||
| 108 | + maskPatUb8[IdxPingPongFlag], | ||
| 109 | + gSparseMask[globalRowOffset * yBlockNumAligned + curLoopColOffset], | ||
| 110 | + AscendC::DataCopyExtParams( | ||
| 111 | + actDealtRowCurLoop, | ||
| 112 | + actDealtColCurLoop * sizeof(ElementSparseMask), | ||
| 113 | + (yBlockNumAligned - actDealtColCurLoop) * sizeof(ElementSparseMask), | ||
| 114 | + 0, 0), | ||
| 115 | + AscendC::DataCopyPadExtParams<ElementSparseMask>( | ||
| 116 | + true, 0, (actDealtColCurLoop32 - actDealtColCurLoop), 0)); | ||
| 117 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(0); | ||
| 118 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(0); | ||
| 119 | + AscendC::Cast( | ||
| 120 | + maskPatUb16, maskPatUb8[IdxPingPongFlag], | ||
| 121 | + AscendC::RoundMode::CAST_NONE, actDealtRowCurLoop * actDealtColCurLoop32); | ||
| 122 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 123 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(IdxPingPongFlag); | ||
| 124 | + | ||
| 125 | + AscendC::Cast( | ||
| 126 | + maskPatUb32, maskPatUb16, | ||
| 127 | + AscendC::RoundMode::CAST_NONE, actDealtRowCurLoop * actDealtColCurLoop32); | ||
| 128 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 129 | + for (uint32_t k = 0; k < actDealtRowCurLoop; k++) { | ||
| 130 | + AscendC::CompareScalar( | ||
| 131 | + maskPatInBitUb8[k * PRE_COL_TILE], | ||
| 132 | + maskPatUb32[k * actDealtColCurLoop32], | ||
| 133 | + static_cast<float>(1.0), AscendC::CMPMODE::GE, actDealtColCurLoop); | ||
| 134 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 135 | + if (k == 0) { | ||
| 136 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(IdxPingPongFlag); | ||
| 137 | + } | ||
| 138 | + AscendC::GatherMask( | ||
| 139 | + sparseIdxUb[IdxPingPongFlag][k * PRE_COL_TILE], | ||
| 140 | + maskIdxUb, | ||
| 141 | + maskPatInBitUb32[k * PRE_COL_TILE / 4], | ||
| 142 | + true, actDealtColCurLoop, {1, 1, 0, 0}, rsvdCountPerRowCurColLoop[k]); | ||
| 143 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(0); | ||
| 144 | + | ||
| 145 | + | ||
| 146 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(0); | ||
| 147 | + if (k == 0) { | ||
| 148 | + AscendC::WaitFlag<AscendC::HardEvent::S_MTE3>(0); | ||
| 149 | + } | ||
| 150 | + AscendC::DataCopyPad( | ||
| 151 | + gSparseIdx[ | ||
| 152 | + globalRowOffset * yBlockNumAligned + k * yBlockNumAligned + | ||
| 153 | + rsvdCountPerRow[k]], | ||
| 154 | + sparseIdxUb[IdxPingPongFlag][k * PRE_COL_TILE], | ||
| 155 | + AscendC::DataCopyExtParams( | ||
| 156 | + 1, rsvdCountPerRowCurColLoop[k] * sizeof(ElementSparseIdx), 0, 0, 0)); | ||
| 157 | + if (k == actDealtRowCurLoop - 1) { | ||
| 158 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(IdxPingPongFlag); | ||
| 159 | + } | ||
| 160 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(0); | ||
| 161 | + | ||
| 162 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(0); | ||
| 163 | + rsvdCountPerRow[k] += rsvdCountPerRowCurColLoop[k]; | ||
| 164 | + if (k == actDealtRowCurLoop - 1) { | ||
| 165 | + AscendC::SetFlag<AscendC::HardEvent::S_MTE3>(0); | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | + IdxPingPongFlag = 1 - IdxPingPongFlag; | ||
| 169 | + } | ||
| 170 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(CountPingPongFlag); | ||
| 171 | + for (uint32_t k = 0; k < actDealtRowCurLoop; k++) { | ||
| 172 | + sparseCountUb[CountPingPongFlag].SetValue(k, static_cast<int32_t>(rsvdCountPerRow[k])); | ||
| 173 | + } | ||
| 174 | + AscendC::SetFlag<AscendC::HardEvent::S_MTE3>(CountPingPongFlag + 2); | ||
| 175 | + AscendC::WaitFlag<AscendC::HardEvent::S_MTE3>(CountPingPongFlag + 2); | ||
| 176 | + AscendC::DataCopyPad( | ||
| 177 | + gSparseCount[globalRowOffset], | ||
| 178 | + sparseCountUb[CountPingPongFlag], | ||
| 179 | + AscendC::DataCopyExtParams(1, actDealtRowCurLoop * sizeof(ElementSparseCount), 0, 0, 0)); | ||
| 180 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(CountPingPongFlag); | ||
| 181 | + | ||
| 182 | + CountPingPongFlag = 1 - CountPingPongFlag; | ||
| 183 | + } | ||
| 184 | + } | ||
| 185 | + } | ||
| 186 | +private: | ||
| 187 | + AscendC::LocalTensor<uint8_t> maskPatUb8[IO_STAGES]; | ||
| 188 | + AscendC::LocalTensor<int32_t> sparseCountUb[IO_STAGES]; | ||
| 189 | + AscendC::LocalTensor<uint8_t> maskPatInBitUb8; | ||
| 190 | + AscendC::LocalTensor<uint32_t> maskPatInBitUb32; | ||
| 191 | + | ||
| 192 | + AscendC::LocalTensor<int32_t> maskIdxUb; | ||
| 193 | + AscendC::LocalTensor<int32_t> sparseIdxUb[IO_STAGES]; | ||
| 194 | + AscendC::LocalTensor<half> maskPatUb16; | ||
| 195 | + AscendC::LocalTensor<float> maskPatUb32; | ||
| 196 | +}; | ||
| 197 | + | ||
| 198 | +} // namespace NpuArch::Epilogue::Block | ||
| 199 | + | ||
| @@ -0,0 +1,1165 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +namespace NpuArch::Epilogue::Block { | ||
| 23 | + | ||
| 24 | +template < | ||
| 25 | + class OutputType_, | ||
| 26 | + class InputType_, | ||
| 27 | + class MaskType_, | ||
| 28 | + LseMode LSE_MODE_> | ||
| 29 | +class BlockEpilogue< | ||
| 30 | + EpilogueAtlasA2OnlineSoftmax<LSE_MODE_, float>, | ||
| 31 | + OutputType_, | ||
| 32 | + InputType_, | ||
| 33 | + MaskType_> | ||
| 34 | +{ | ||
| 35 | +public: | ||
| 36 | + using DispatchPolicy = EpilogueAtlasA2OnlineSoftmax<LSE_MODE_, float>; | ||
| 37 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 38 | + using ElementOutput = typename OutputType_::Element; | ||
| 39 | + using ElementInput = typename InputType_::Element; | ||
| 40 | + using ElementMask = typename MaskType_::Element; | ||
| 41 | + | ||
| 42 | + using LayoutOutput = typename OutputType_::Layout; | ||
| 43 | + using LayoutInput = typename InputType_::Layout; | ||
| 44 | + using LayoutMask = typename MaskType_::Layout; | ||
| 45 | + | ||
| 46 | + static constexpr LseMode LSE_MODE = DispatchPolicy::LSE_MODE; | ||
| 47 | + | ||
| 48 | + static constexpr uint32_t BLOCK_SIZE_IN_BYTE = 32; | ||
| 49 | + static constexpr uint32_t REPEAT_SIZE_IN_BYTE = 256; | ||
| 50 | + static constexpr uint32_t FLOAT_BLOCK_SIZE = 8; | ||
| 51 | + static constexpr uint32_t FLOAT_VECTOR_SIZE = 64; | ||
| 52 | + static constexpr uint32_t HALF_VECTOR_SIZE = 128; | ||
| 53 | + static constexpr uint32_t BLOCK_SIZE = 16; | ||
| 54 | + static constexpr uint32_t UB_UINT8_VECTOR_SIZE = 1024; | ||
| 55 | + static constexpr uint32_t UB_UINT8_BLOCK_SIZE = 16384; | ||
| 56 | + static constexpr uint32_t VECTOR_SIZE = 128; | ||
| 57 | + static constexpr uint32_t MAX_UB_S_ELEM_NUM = 8192; | ||
| 58 | + | ||
| 59 | + static constexpr uint32_t REDUCE_UB_SIZE = 1024; | ||
| 60 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_32 = 32; | ||
| 61 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_16 = 16; | ||
| 62 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_4 = 4; | ||
| 63 | + static constexpr uint32_t MAX_ROW_NUM_SUB_CORE = 256; | ||
| 64 | + static constexpr int64_t UB_FLOAT_LINE_SIZE = 64; | ||
| 65 | + | ||
| 66 | + __aicore__ inline | ||
| 67 | + BlockEpilogue(Arch::Resource<ArchTag> &resource, float scaleValue_) | ||
| 68 | + { | ||
| 69 | + // Allocate UB space | ||
| 70 | + constexpr uint32_t LS_UB_TENSOR_OFFSET = 0; | ||
| 71 | + constexpr uint32_t LP_UB_TENSOR_OFFSET = 4 * UB_UINT8_BLOCK_SIZE; | ||
| 72 | + constexpr uint32_t MASK_UB_TENSOR_OFFSET = 4 * UB_UINT8_BLOCK_SIZE; | ||
| 73 | + constexpr uint32_t MASK32_UB_TENSOR_OFFSET = 4 * UB_UINT8_BLOCK_SIZE; | ||
| 74 | + | ||
| 75 | + constexpr uint32_t TV_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE; | ||
| 76 | + constexpr uint32_t LM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 8 * UB_UINT8_VECTOR_SIZE; | ||
| 77 | + | ||
| 78 | + constexpr uint32_t HM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 9 * UB_UINT8_VECTOR_SIZE; | ||
| 79 | + constexpr uint32_t GM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 10 * UB_UINT8_VECTOR_SIZE; | ||
| 80 | + constexpr uint32_t LL_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 11 * UB_UINT8_VECTOR_SIZE; | ||
| 81 | + constexpr uint32_t GL_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 12 * UB_UINT8_VECTOR_SIZE; | ||
| 82 | + constexpr uint32_t DM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 13 * UB_UINT8_VECTOR_SIZE; | ||
| 83 | + | ||
| 84 | + constexpr uint32_t MASK16_UB_TENSOR_OFFSET = 11 * UB_UINT8_BLOCK_SIZE; | ||
| 85 | + | ||
| 86 | + scaleValue = scaleValue_; | ||
| 87 | + lsUbTensor = resource.ubBuf.template GetBufferByByte<float>(LS_UB_TENSOR_OFFSET); | ||
| 88 | + lpUbTensor = resource.ubBuf.template GetBufferByByte<ElementOutput>(LP_UB_TENSOR_OFFSET); | ||
| 89 | + maskUbTensor = resource.ubBuf.template GetBufferByByte<ElementMask>(MASK_UB_TENSOR_OFFSET); | ||
| 90 | + maskUbTensor16 = resource.ubBuf.template GetBufferByByte<half>(MASK16_UB_TENSOR_OFFSET); | ||
| 91 | + maskUbTensor32 = resource.ubBuf.template GetBufferByByte<float>(MASK32_UB_TENSOR_OFFSET); | ||
| 92 | + lmUbTensor = resource.ubBuf.template GetBufferByByte<float>(LM_UB_TENSOR_OFFSET); | ||
| 93 | + hmUbTensor = resource.ubBuf.template GetBufferByByte<float>(HM_UB_TENSOR_OFFSET); | ||
| 94 | + gmUbTensor = resource.ubBuf.template GetBufferByByte<float>(GM_UB_TENSOR_OFFSET); | ||
| 95 | + dmUbTensor = resource.ubBuf.template GetBufferByByte<float>(DM_UB_TENSOR_OFFSET); | ||
| 96 | + llUbTensor = resource.ubBuf.template GetBufferByByte<float>(LL_UB_TENSOR_OFFSET); | ||
| 97 | + tvUbTensor = resource.ubBuf.template GetBufferByByte<float>(TV_UB_TENSOR_OFFSET); | ||
| 98 | + glUbTensor = resource.ubBuf.template GetBufferByByte<float>(GL_UB_TENSOR_OFFSET); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + __aicore__ inline | ||
| 102 | + ~BlockEpilogue() {} | ||
| 103 | + | ||
| 104 | + template <typename T> | ||
| 105 | + __aicore__ inline T Min(T a, T b) | ||
| 106 | + { | ||
| 107 | + return (a > b) ? b : a; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + __aicore__ inline | ||
| 111 | + void SetVecMask(int32_t len) | ||
| 112 | + { | ||
| 113 | + uint64_t mask = 0; | ||
| 114 | + uint64_t one = 1; | ||
| 115 | + uint64_t temp = len % FLOAT_VECTOR_SIZE; | ||
| 116 | + for (int64_t i = 0; i < temp; i++) { | ||
| 117 | + mask |= one << i; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + if (len == VECTOR_SIZE || len == 0) { | ||
| 121 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 122 | + } else if (len >= FLOAT_VECTOR_SIZE) { | ||
| 123 | + AscendC::SetVectorMask<int8_t>(mask, (uint64_t)-1); | ||
| 124 | + } else { | ||
| 125 | + AscendC::SetVectorMask<int8_t>(0x0, mask); | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + __aicore__ inline | ||
| 130 | + void SetBlockReduceMask(int32_t len) | ||
| 131 | + { | ||
| 132 | + if (len > 8 || len < 1) { | ||
| 133 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 134 | + return; | ||
| 135 | + } | ||
| 136 | + uint64_t subMask = ((uint64_t)1 << len) - 1; | ||
| 137 | + uint64_t maskValue = (subMask << 48) + (subMask << 32) + (subMask << 16) + subMask + (subMask << 56) + | ||
| 138 | + (subMask << 40) + (subMask << 24) + (subMask << 8); | ||
| 139 | + AscendC::SetVectorMask<int8_t>(maskValue, maskValue); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + __aicore__ inline | ||
| 143 | + void RowsumSPECTILE1024(const AscendC::LocalTensor<float> &srcUb, const AscendC::LocalTensor<float> &rowsumUb, | ||
| 144 | + const AscendC::LocalTensor<float> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 145 | + uint32_t numElemsAligned) | ||
| 146 | + { | ||
| 147 | + AscendC::BlockReduceSum<float, false>( | ||
| 148 | + tvUbTensor, | ||
| 149 | + srcUb, | ||
| 150 | + numRowsRound * numElemsAligned / FLOAT_VECTOR_SIZE, | ||
| 151 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 152 | + 1, | ||
| 153 | + 1, | ||
| 154 | + 8); | ||
| 155 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 156 | + | ||
| 157 | + AscendC::BlockReduceSum<float, false>( | ||
| 158 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 159 | + tvUbTensor, | ||
| 160 | + numRowsRound * numElemsAligned / FLOAT_BLOCK_SIZE / FLOAT_VECTOR_SIZE, | ||
| 161 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 162 | + 1, | ||
| 163 | + 1, | ||
| 164 | + 8); | ||
| 165 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 166 | + | ||
| 167 | + SetVecMask(ROW_OPS_SPEC_MASK_16); | ||
| 168 | + AscendC::WholeReduceSum<float, false>( | ||
| 169 | + rowsumUb, | ||
| 170 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 171 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 172 | + numRowsRound, | ||
| 173 | + 1, | ||
| 174 | + 1, | ||
| 175 | + 2); | ||
| 176 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 177 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + __aicore__ inline | ||
| 181 | + void RowsumSPECTILE512(const AscendC::LocalTensor<float> &srcUb, const AscendC::LocalTensor<float> &rowsumUb, | ||
| 182 | + const AscendC::LocalTensor<float> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 183 | + uint32_t numElemsAligned) | ||
| 184 | + { | ||
| 185 | + AscendC::BlockReduceSum<float, false>( | ||
| 186 | + tvUbTensor, | ||
| 187 | + srcUb, | ||
| 188 | + numRowsRound * numElemsAligned / FLOAT_VECTOR_SIZE, | ||
| 189 | + 0, 1, 1, 8); | ||
| 190 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 191 | + | ||
| 192 | + AscendC::BlockReduceSum<float, false>( | ||
| 193 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 194 | + tvUbTensor, | ||
| 195 | + numRowsRound * numElemsAligned / FLOAT_BLOCK_SIZE / FLOAT_VECTOR_SIZE, | ||
| 196 | + 0, 1, 1, 8); | ||
| 197 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 198 | + AscendC::BlockReduceSum<float, false>( | ||
| 199 | + rowsumUb, | ||
| 200 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 201 | + numRowsRound * numElemsAligned / FLOAT_VECTOR_SIZE / FLOAT_VECTOR_SIZE, | ||
| 202 | + 0, 1, 1, 8); | ||
| 203 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + __aicore__ inline | ||
| 207 | + void RowsumSPECTILE256(const AscendC::LocalTensor<float> &srcUb, const AscendC::LocalTensor<float> &rowsumUb, | ||
| 208 | + const AscendC::LocalTensor<float> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 209 | + uint32_t numElemsAligned) | ||
| 210 | + { | ||
| 211 | + AscendC::BlockReduceSum<float, false>( | ||
| 212 | + tvUbTensor, | ||
| 213 | + srcUb, | ||
| 214 | + numRowsRound * numElemsAligned / FLOAT_VECTOR_SIZE, | ||
| 215 | + 0, 1, 1, 8); | ||
| 216 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 217 | + SetVecMask(ROW_OPS_SPEC_MASK_32); | ||
| 218 | + AscendC::BlockReduceSum<float, false>( | ||
| 219 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 220 | + tvUbTensor, | ||
| 221 | + numRowsRound, | ||
| 222 | + 0, 1, 1, 4); | ||
| 223 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 224 | + SetBlockReduceMask(ROW_OPS_SPEC_MASK_4); | ||
| 225 | + AscendC::BlockReduceSum<float, false>( | ||
| 226 | + rowsumUb, | ||
| 227 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 228 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 229 | + 0, 1, 1, 8); | ||
| 230 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 231 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + __aicore__ inline | ||
| 235 | + void RowsumTAILTILE(const AscendC::LocalTensor<float> &srcUb, const AscendC::LocalTensor<float> &rowsumUb, | ||
| 236 | + const AscendC::LocalTensor<float> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 237 | + uint32_t numElemsAligned) | ||
| 238 | + { | ||
| 239 | + if (numElems >= FLOAT_VECTOR_SIZE) { | ||
| 240 | + AscendC::BlockReduceSum<float, false>( | ||
| 241 | + tvUbTensor, | ||
| 242 | + srcUb, | ||
| 243 | + numRowsRound, | ||
| 244 | + 0, 1, 1, numElemsAligned / FLOAT_BLOCK_SIZE); | ||
| 245 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 246 | + AscendC::BlockReduceSum<float, false>( | ||
| 247 | + rowsumUb, | ||
| 248 | + tvUbTensor, | ||
| 249 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 250 | + 0, 1, 1, 8); | ||
| 251 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 252 | + for (uint64_t rowSumIdx = 1; rowSumIdx < (uint64_t)numElems / FLOAT_VECTOR_SIZE; ++rowSumIdx) { | ||
| 253 | + AscendC::BlockReduceSum<float, false>( | ||
| 254 | + tvUbTensor, | ||
| 255 | + srcUb[rowSumIdx * FLOAT_VECTOR_SIZE], | ||
| 256 | + numRowsRound, | ||
| 257 | + 0, 1, 1, numElemsAligned / FLOAT_BLOCK_SIZE); | ||
| 258 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 259 | + AscendC::BlockReduceSum<float, false>( | ||
| 260 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 261 | + tvUbTensor, | ||
| 262 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 263 | + 0, 1, 1, 8); | ||
| 264 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 265 | + SetVecMask(numRowsRound); | ||
| 266 | + AscendC::Add<float, false>( | ||
| 267 | + rowsumUb, | ||
| 268 | + rowsumUb, | ||
| 269 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 270 | + (uint64_t)0, | ||
| 271 | + 1, | ||
| 272 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 273 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 274 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 275 | + } | ||
| 276 | + } | ||
| 277 | + if (numElems % FLOAT_VECTOR_SIZE > 0) { | ||
| 278 | + SetVecMask(numElems % FLOAT_VECTOR_SIZE); | ||
| 279 | + AscendC::BlockReduceSum<float, false>( | ||
| 280 | + tvUbTensor, | ||
| 281 | + srcUb[numElems / FLOAT_VECTOR_SIZE * FLOAT_VECTOR_SIZE], | ||
| 282 | + numRowsRound, | ||
| 283 | + 0, 1, 1, numElemsAligned / FLOAT_BLOCK_SIZE); | ||
| 284 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 285 | + SetBlockReduceMask(CeilDiv(numElems % FLOAT_VECTOR_SIZE, FLOAT_BLOCK_SIZE)); | ||
| 286 | + if (numElems < FLOAT_VECTOR_SIZE) { | ||
| 287 | + AscendC::BlockReduceSum<float, false>( | ||
| 288 | + rowsumUb, | ||
| 289 | + tvUbTensor, | ||
| 290 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 291 | + 0, 1, 1, 8); | ||
| 292 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 293 | + } else { | ||
| 294 | + AscendC::BlockReduceSum<float, false>( | ||
| 295 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 296 | + tvUbTensor, | ||
| 297 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 298 | + 0, 1, 1, 8); | ||
| 299 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 300 | + SetVecMask(numRowsRound); | ||
| 301 | + AscendC::Add<float, false>( | ||
| 302 | + rowsumUb, | ||
| 303 | + rowsumUb, | ||
| 304 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 305 | + (uint64_t)0, | ||
| 306 | + 1, | ||
| 307 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 308 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 309 | + } | ||
| 310 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 311 | + } | ||
| 312 | + } | ||
| 313 | + | ||
| 314 | + __aicore__ inline | ||
| 315 | + void RowmaxSPECTILE1024(const AscendC::LocalTensor<float> &srcUb, const AscendC::LocalTensor<float> &rowmaxUb, | ||
| 316 | + const AscendC::LocalTensor<float> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 317 | + uint32_t numElemsAligned) | ||
| 318 | + { | ||
| 319 | + AscendC::BlockReduceMax<float, false>( | ||
| 320 | + tvUbTensor, | ||
| 321 | + srcUb, | ||
| 322 | + numRowsRound * numElemsAligned / FLOAT_VECTOR_SIZE, | ||
| 323 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 324 | + 1, | ||
| 325 | + 1, | ||
| 326 | + 8); | ||
| 327 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 328 | + | ||
| 329 | + AscendC::BlockReduceMax<float, false>( | ||
| 330 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 331 | + tvUbTensor, | ||
| 332 | + numRowsRound * numElemsAligned / FLOAT_BLOCK_SIZE / FLOAT_VECTOR_SIZE, | ||
| 333 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 334 | + 1, | ||
| 335 | + 1, | ||
| 336 | + 8); | ||
| 337 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 338 | + | ||
| 339 | + SetVecMask(ROW_OPS_SPEC_MASK_16); | ||
| 340 | + AscendC::WholeReduceMax<float, false>( | ||
| 341 | + rowmaxUb, | ||
| 342 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 343 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 344 | + numRowsRound, | ||
| 345 | + 1, | ||
| 346 | + 1, | ||
| 347 | + 2, | ||
| 348 | + AscendC::ReduceOrder::ORDER_ONLY_VALUE); | ||
| 349 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 350 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 351 | + } | ||
| 352 | + | ||
| 353 | + __aicore__ inline | ||
| 354 | + void RowmaxSPECTILE512(const AscendC::LocalTensor<float> &srcUb, const AscendC::LocalTensor<float> &rowmaxUb, | ||
| 355 | + const AscendC::LocalTensor<float> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 356 | + uint32_t numElemsAligned) | ||
| 357 | + { | ||
| 358 | + AscendC::BlockReduceMax<float, false>( | ||
| 359 | + tvUbTensor, | ||
| 360 | + srcUb, | ||
| 361 | + numRowsRound * numElemsAligned / FLOAT_VECTOR_SIZE, | ||
| 362 | + 0, 1, 1, 8); | ||
| 363 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 364 | + AscendC::BlockReduceMax<float, false>( | ||
| 365 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 366 | + tvUbTensor, | ||
| 367 | + numRowsRound * numElemsAligned / FLOAT_BLOCK_SIZE / FLOAT_VECTOR_SIZE, | ||
| 368 | + 0, 1, 1, 8); | ||
| 369 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 370 | + AscendC::BlockReduceMax<float, false>( | ||
| 371 | + rowmaxUb, | ||
| 372 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 373 | + numRowsRound * numElemsAligned / FLOAT_VECTOR_SIZE / FLOAT_VECTOR_SIZE, | ||
| 374 | + 0, 1, 1, 8); | ||
| 375 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + __aicore__ inline | ||
| 379 | + void RowmaxSPECTILE256(const AscendC::LocalTensor<float> &srcUb, const AscendC::LocalTensor<float> &rowmaxUb, | ||
| 380 | + const AscendC::LocalTensor<float> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 381 | + uint32_t numElemsAligned) | ||
| 382 | + { | ||
| 383 | + AscendC::BlockReduceMax<float, false>( | ||
| 384 | + tvUbTensor, | ||
| 385 | + srcUb, | ||
| 386 | + numRowsRound * numElemsAligned / FLOAT_VECTOR_SIZE, | ||
| 387 | + 0, 1, 1, 8); | ||
| 388 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 389 | + SetVecMask(ROW_OPS_SPEC_MASK_32); | ||
| 390 | + AscendC::BlockReduceMax<float, false>( | ||
| 391 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 392 | + tvUbTensor, | ||
| 393 | + numRowsRound, | ||
| 394 | + 0, 1, 1, 4); | ||
| 395 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 396 | + SetBlockReduceMask(ROW_OPS_SPEC_MASK_4); | ||
| 397 | + AscendC::BlockReduceMax<float, false>( | ||
| 398 | + rowmaxUb, | ||
| 399 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 400 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 401 | + 0, 1, 1, 8); | ||
| 402 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 403 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 404 | + } | ||
| 405 | + | ||
| 406 | + __aicore__ inline | ||
| 407 | + void RowmaxTAILTILE(const AscendC::LocalTensor<float> &srcUb, const AscendC::LocalTensor<float> &rowmaxUb, | ||
| 408 | + const AscendC::LocalTensor<float> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 409 | + uint32_t numElemsAligned) | ||
| 410 | + { | ||
| 411 | + if (numElems >= FLOAT_VECTOR_SIZE) { | ||
| 412 | + AscendC::BlockReduceMax<float, false>( | ||
| 413 | + tvUbTensor, | ||
| 414 | + srcUb, | ||
| 415 | + numRowsRound, | ||
| 416 | + 0, 1, 1, numElemsAligned / FLOAT_BLOCK_SIZE); | ||
| 417 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 418 | + AscendC::BlockReduceMax<float, false>( | ||
| 419 | + rowmaxUb, | ||
| 420 | + tvUbTensor, | ||
| 421 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 422 | + 0, 1, 1, 8); | ||
| 423 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 424 | + for (uint64_t rowmax_idx = 1; rowmax_idx < (uint64_t)numElems / FLOAT_VECTOR_SIZE; ++rowmax_idx) { | ||
| 425 | + AscendC::BlockReduceMax<float, false>( | ||
| 426 | + tvUbTensor, | ||
| 427 | + srcUb[rowmax_idx * FLOAT_VECTOR_SIZE], | ||
| 428 | + numRowsRound, | ||
| 429 | + 0, 1, 1, numElemsAligned / FLOAT_BLOCK_SIZE); | ||
| 430 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 431 | + AscendC::BlockReduceMax<float, false>( | ||
| 432 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 433 | + tvUbTensor, | ||
| 434 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 435 | + 0, 1, 1, 8); | ||
| 436 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 437 | + SetVecMask(numRowsRound); | ||
| 438 | + AscendC::Max<float, false>(rowmaxUb, | ||
| 439 | + rowmaxUb, | ||
| 440 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 441 | + (uint64_t)0, | ||
| 442 | + 1, | ||
| 443 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 444 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 445 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 446 | + } | ||
| 447 | + } | ||
| 448 | + if (numElems % FLOAT_VECTOR_SIZE > 0) { | ||
| 449 | + SetVecMask(numElems % FLOAT_VECTOR_SIZE); | ||
| 450 | + AscendC::BlockReduceMax<float, false>( | ||
| 451 | + tvUbTensor, | ||
| 452 | + srcUb[numElems / FLOAT_VECTOR_SIZE * FLOAT_VECTOR_SIZE], | ||
| 453 | + numRowsRound, | ||
| 454 | + 0, 1, 1, numElemsAligned / FLOAT_BLOCK_SIZE); | ||
| 455 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 456 | + SetBlockReduceMask(CeilDiv(numElems % FLOAT_VECTOR_SIZE, FLOAT_BLOCK_SIZE)); | ||
| 457 | + if (numElems < FLOAT_VECTOR_SIZE) { | ||
| 458 | + AscendC::BlockReduceMax<float, false>(rowmaxUb, | ||
| 459 | + tvUbTensor, | ||
| 460 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 461 | + 0, 1, 1, 8); | ||
| 462 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 463 | + } else { | ||
| 464 | + AscendC::BlockReduceMax<float, false>(tvUbTensor[REDUCE_UB_SIZE], | ||
| 465 | + tvUbTensor, | ||
| 466 | + CeilDiv(numRowsRound * FLOAT_BLOCK_SIZE, FLOAT_VECTOR_SIZE), | ||
| 467 | + 0, 1, 1, 8); | ||
| 468 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 469 | + SetVecMask(numRowsRound); | ||
| 470 | + AscendC::Max<float, false>(rowmaxUb, | ||
| 471 | + rowmaxUb, | ||
| 472 | + tvUbTensor[REDUCE_UB_SIZE], | ||
| 473 | + (uint64_t)0, | ||
| 474 | + 1, | ||
| 475 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 476 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 477 | + } | ||
| 478 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 479 | + } | ||
| 480 | + } | ||
| 481 | + | ||
| 482 | + __aicore__ inline | ||
| 483 | + void CopySGmToUb( | ||
| 484 | + AscendC::GlobalTensor<ElementInput> gInput, | ||
| 485 | + uint32_t sUbOffset, | ||
| 486 | + uint32_t rowNumCurLoop, | ||
| 487 | + uint32_t columnNumRound, | ||
| 488 | + uint32_t columnNumPad) | ||
| 489 | + { | ||
| 490 | + AscendC::DataCopy( | ||
| 491 | + lsUbTensor[sUbOffset], | ||
| 492 | + gInput, | ||
| 493 | + AscendC::DataCopyParams( | ||
| 494 | + rowNumCurLoop, columnNumRound / FLOAT_BLOCK_SIZE, | ||
| 495 | + (columnNumPad - columnNumRound) / FLOAT_BLOCK_SIZE, 0)); | ||
| 496 | + } | ||
| 497 | + | ||
| 498 | + __aicore__ inline | ||
| 499 | + void CopyMaskGmToUb( | ||
| 500 | + AscendC::GlobalTensor<ElementMask> gMask, | ||
| 501 | + uint32_t columnNum, uint32_t columnNumRound, | ||
| 502 | + uint32_t maskStride, uint32_t tokenNumPerHead, | ||
| 503 | + uint32_t proTokenIdx, uint32_t proTokenNum, | ||
| 504 | + uint32_t integralHeadNum, uint32_t epiTokenNum) | ||
| 505 | + { | ||
| 506 | + uint32_t innerUbRowOffset = 0; | ||
| 507 | + if (proTokenNum != 0) { | ||
| 508 | + AscendC::DataCopyPad( | ||
| 509 | + maskUbTensor[innerUbRowOffset], gMask[proTokenIdx * maskStride], | ||
| 510 | + AscendC::DataCopyExtParams( | ||
| 511 | + proTokenNum, columnNum * sizeof(ElementMask), | ||
| 512 | + (maskStride - columnNum) * sizeof(ElementMask), 0, 0), | ||
| 513 | + AscendC::DataCopyPadExtParams<ElementMask>(false, 0, 0, 0)); | ||
| 514 | + innerUbRowOffset += proTokenNum * columnNumRound; | ||
| 515 | + } | ||
| 516 | + for (uint32_t headIdx = 0; headIdx < integralHeadNum; headIdx++) { | ||
| 517 | + AscendC::DataCopyPad( | ||
| 518 | + maskUbTensor[innerUbRowOffset], gMask, | ||
| 519 | + AscendC::DataCopyExtParams( | ||
| 520 | + tokenNumPerHead, columnNum * sizeof(ElementMask), | ||
| 521 | + (maskStride - columnNum) * sizeof(ElementMask), 0, 0), | ||
| 522 | + AscendC::DataCopyPadExtParams<ElementMask>(false, 0, 0, 0)); | ||
| 523 | + innerUbRowOffset += tokenNumPerHead * columnNumRound; | ||
| 524 | + } | ||
| 525 | + if (epiTokenNum != 0) { | ||
| 526 | + AscendC::DataCopyPad( | ||
| 527 | + maskUbTensor[innerUbRowOffset], gMask, | ||
| 528 | + AscendC::DataCopyExtParams( | ||
| 529 | + epiTokenNum, columnNum * sizeof(ElementMask), | ||
| 530 | + (maskStride - columnNum) * sizeof(ElementMask), 0, 0), | ||
| 531 | + AscendC::DataCopyPadExtParams<ElementMask>(false, 0, 0, 0)); | ||
| 532 | + } | ||
| 533 | + } | ||
| 534 | + | ||
| 535 | + __aicore__ inline | ||
| 536 | + void ScaleS(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t columnNumRound) | ||
| 537 | + { | ||
| 538 | + AscendC::Muls<float, false>( | ||
| 539 | + lsUbTensor[sUbOffset], | ||
| 540 | + lsUbTensor[sUbOffset], | ||
| 541 | + scaleValue, | ||
| 542 | + (uint64_t)0, | ||
| 543 | + CeilDiv(rowNumCurLoop * columnNumRound, FLOAT_VECTOR_SIZE), | ||
| 544 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 545 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 546 | + } | ||
| 547 | + | ||
| 548 | + template<typename ElementMaskDst, typename ElementMaskSrc> | ||
| 549 | + __aicore__ inline | ||
| 550 | + void UpCastMask( | ||
| 551 | + const AscendC::LocalTensor<ElementMaskDst> &maskUbTensorDst, | ||
| 552 | + const AscendC::LocalTensor<ElementMaskSrc> &maskUbTensorSrc, | ||
| 553 | + uint32_t rowNumCurLoop, | ||
| 554 | + uint32_t columnNumRound) | ||
| 555 | + { | ||
| 556 | + AscendC::Cast<ElementMaskDst, ElementMaskSrc, false>( | ||
| 557 | + maskUbTensorDst, maskUbTensorSrc, AscendC::RoundMode::CAST_NONE, (uint64_t)0, | ||
| 558 | + CeilDiv(rowNumCurLoop * columnNumRound, (uint32_t)(REPEAT_SIZE_IN_BYTE / sizeof(ElementMaskDst))), | ||
| 559 | + AscendC::UnaryRepeatParams(1, 1, 8, 4)); | ||
| 560 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 561 | + } | ||
| 562 | + | ||
| 563 | + __aicore__ inline | ||
| 564 | + void ApplyMask(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t columnNumRound, uint32_t maskColumnRound, | ||
| 565 | + uint32_t addMaskUbOffset) | ||
| 566 | + { | ||
| 567 | + AscendC::Muls<float, false>( | ||
| 568 | + maskUbTensor32, | ||
| 569 | + maskUbTensor32, | ||
| 570 | + (float)-3e38, | ||
| 571 | + (uint64_t)0, | ||
| 572 | + CeilDiv(rowNumCurLoop * maskColumnRound, FLOAT_VECTOR_SIZE), | ||
| 573 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 574 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 575 | + if (maskColumnRound == columnNumRound) { | ||
| 576 | + AscendC::Add<float, false>( | ||
| 577 | + lsUbTensor[sUbOffset], | ||
| 578 | + lsUbTensor[sUbOffset], | ||
| 579 | + maskUbTensor32, | ||
| 580 | + (uint64_t)0, | ||
| 581 | + CeilDiv(rowNumCurLoop * maskColumnRound, FLOAT_VECTOR_SIZE), | ||
| 582 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 583 | + } else { | ||
| 584 | + uint32_t loop = maskColumnRound / FLOAT_VECTOR_SIZE; | ||
| 585 | + for (uint32_t i = 0; i < loop; i++) { | ||
| 586 | + AscendC::Add<float, false>(lsUbTensor[sUbOffset][addMaskUbOffset + i * FLOAT_VECTOR_SIZE], | ||
| 587 | + lsUbTensor[sUbOffset][addMaskUbOffset + i * FLOAT_VECTOR_SIZE], | ||
| 588 | + maskUbTensor32[i * FLOAT_VECTOR_SIZE], | ||
| 589 | + (uint64_t)0, | ||
| 590 | + rowNumCurLoop, | ||
| 591 | + AscendC::BinaryRepeatParams( | ||
| 592 | + 1, 1, 1, | ||
| 593 | + columnNumRound / FLOAT_BLOCK_SIZE, | ||
| 594 | + columnNumRound / FLOAT_BLOCK_SIZE, | ||
| 595 | + maskColumnRound / FLOAT_BLOCK_SIZE)); | ||
| 596 | + } | ||
| 597 | + if (maskColumnRound % FLOAT_VECTOR_SIZE > 0) { | ||
| 598 | + SetVecMask(maskColumnRound % FLOAT_VECTOR_SIZE); | ||
| 599 | + AscendC::Add<float, false>(lsUbTensor[sUbOffset][addMaskUbOffset + loop * FLOAT_VECTOR_SIZE], | ||
| 600 | + lsUbTensor[sUbOffset][addMaskUbOffset + loop * FLOAT_VECTOR_SIZE], | ||
| 601 | + maskUbTensor32[loop * FLOAT_VECTOR_SIZE], | ||
| 602 | + (uint64_t)0, | ||
| 603 | + rowNumCurLoop, | ||
| 604 | + AscendC::BinaryRepeatParams( | ||
| 605 | + 1, 1, 1, | ||
| 606 | + columnNumRound / FLOAT_BLOCK_SIZE, | ||
| 607 | + columnNumRound / FLOAT_BLOCK_SIZE, | ||
| 608 | + maskColumnRound / FLOAT_BLOCK_SIZE)); | ||
| 609 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 610 | + } | ||
| 611 | + } | ||
| 612 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 613 | + } | ||
| 614 | + | ||
| 615 | + __aicore__ inline | ||
| 616 | + void CalcLocalRowMax(uint32_t sUbOffset, uint32_t rowNumCurLoopRound, uint32_t columnNum, uint32_t columnNumRound, | ||
| 617 | + uint32_t rowOffset) | ||
| 618 | + { | ||
| 619 | + if (columnNum == 1024) { | ||
| 620 | + RowmaxSPECTILE1024( | ||
| 621 | + lsUbTensor[sUbOffset], | ||
| 622 | + lmUbTensor[rowOffset], | ||
| 623 | + tvUbTensor, | ||
| 624 | + rowNumCurLoopRound, | ||
| 625 | + columnNum, | ||
| 626 | + columnNumRound); | ||
| 627 | + } else if (columnNum == 512) { | ||
| 628 | + RowmaxSPECTILE512( | ||
| 629 | + lsUbTensor[sUbOffset], | ||
| 630 | + lmUbTensor[rowOffset], | ||
| 631 | + tvUbTensor, | ||
| 632 | + rowNumCurLoopRound, | ||
| 633 | + columnNum, | ||
| 634 | + columnNumRound); | ||
| 635 | + } else if (columnNum == 256) { | ||
| 636 | + RowmaxSPECTILE256( | ||
| 637 | + lsUbTensor[sUbOffset], | ||
| 638 | + lmUbTensor[rowOffset], | ||
| 639 | + tvUbTensor, | ||
| 640 | + rowNumCurLoopRound, | ||
| 641 | + columnNum, | ||
| 642 | + columnNumRound); | ||
| 643 | + } else { | ||
| 644 | + RowmaxTAILTILE( | ||
| 645 | + lsUbTensor[sUbOffset], | ||
| 646 | + lmUbTensor[rowOffset], | ||
| 647 | + tvUbTensor, | ||
| 648 | + rowNumCurLoopRound, | ||
| 649 | + columnNum, | ||
| 650 | + columnNumRound); | ||
| 651 | + } | ||
| 652 | + } | ||
| 653 | + | ||
| 654 | + __aicore__ inline | ||
| 655 | + void UpdateGlobalRowMax(uint32_t rowNumCurLoop, uint32_t rowNumCurLoopRound, uint32_t columnNum, | ||
| 656 | + uint32_t columnNumRound, uint32_t dmUbOffsetCurCycle, uint32_t rowOffset, uint32_t isFirstStackTile) | ||
| 657 | + { | ||
| 658 | + if (isFirstStackTile) { | ||
| 659 | + AscendC::DataCopy( | ||
| 660 | + hmUbTensor[rowOffset], | ||
| 661 | + lmUbTensor[rowOffset], | ||
| 662 | + AscendC::DataCopyParams(1, rowNumCurLoopRound / FLOAT_BLOCK_SIZE, 0, 0)); | ||
| 663 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 664 | + } else { | ||
| 665 | + SetVecMask(rowNumCurLoop); | ||
| 666 | + // *** hm = vmax(lm, gm) | ||
| 667 | + AscendC::Max<float, false>( | ||
| 668 | + hmUbTensor[rowOffset], | ||
| 669 | + lmUbTensor[rowOffset], | ||
| 670 | + gmUbTensor[rowOffset], | ||
| 671 | + (uint64_t)0, | ||
| 672 | + 1, | ||
| 673 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 674 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 675 | + // *** dm = gm - hm | ||
| 676 | + AscendC::Sub<float, false>( | ||
| 677 | + dmUbTensor[dmUbOffsetCurCycle], | ||
| 678 | + gmUbTensor[rowOffset], | ||
| 679 | + hmUbTensor[rowOffset], | ||
| 680 | + (uint64_t)0, | ||
| 681 | + 1, | ||
| 682 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 683 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 684 | + // *** dm = exp(dm) | ||
| 685 | + AscendC::Exp<float, false>( | ||
| 686 | + dmUbTensor[dmUbOffsetCurCycle], | ||
| 687 | + dmUbTensor[dmUbOffsetCurCycle], | ||
| 688 | + (uint64_t)0, | ||
| 689 | + 1, | ||
| 690 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 691 | + } | ||
| 692 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 693 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 694 | + // *** gm = hm | ||
| 695 | + AscendC::DataCopy( | ||
| 696 | + gmUbTensor[rowOffset], | ||
| 697 | + hmUbTensor[rowOffset], | ||
| 698 | + AscendC::DataCopyParams(1, rowNumCurLoopRound / FLOAT_BLOCK_SIZE, 0, 0)); | ||
| 699 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 700 | + } | ||
| 701 | + | ||
| 702 | + __aicore__ inline | ||
| 703 | + void CalcExp(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t rowNumCurLoopRound, uint32_t columnNum, | ||
| 704 | + uint32_t columnNumRound, uint32_t rowOffset) | ||
| 705 | + { | ||
| 706 | + // *** hm_block = expand_to_block(hm), 存放于 tv | ||
| 707 | + AscendC::Brcb( | ||
| 708 | + tvUbTensor.template ReinterpretCast<uint32_t>(), | ||
| 709 | + hmUbTensor[rowOffset].template ReinterpretCast<uint32_t>(), | ||
| 710 | + rowNumCurLoopRound / FLOAT_BLOCK_SIZE, | ||
| 711 | + AscendC::BrcbRepeatParams(1, 8)); | ||
| 712 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 713 | + // *** ls = ls - hm_block | ||
| 714 | + for (uint32_t subIdx = 0; subIdx < columnNum / FLOAT_VECTOR_SIZE; ++subIdx) { | ||
| 715 | + AscendC::Sub<float, false>( | ||
| 716 | + lsUbTensor[sUbOffset][subIdx * FLOAT_VECTOR_SIZE], | ||
| 717 | + lsUbTensor[sUbOffset][subIdx * FLOAT_VECTOR_SIZE], | ||
| 718 | + tvUbTensor, | ||
| 719 | + (uint64_t)0, | ||
| 720 | + rowNumCurLoop, | ||
| 721 | + AscendC::BinaryRepeatParams( | ||
| 722 | + 1, 1, 0, columnNumRound / FLOAT_BLOCK_SIZE, columnNumRound / FLOAT_BLOCK_SIZE, 1)); | ||
| 723 | + } | ||
| 724 | + if (columnNum % FLOAT_VECTOR_SIZE > 0) { | ||
| 725 | + SetVecMask(columnNum % FLOAT_VECTOR_SIZE); | ||
| 726 | + AscendC::Sub<float, false>( | ||
| 727 | + lsUbTensor[sUbOffset][columnNum / FLOAT_VECTOR_SIZE * FLOAT_VECTOR_SIZE], | ||
| 728 | + lsUbTensor[sUbOffset][columnNum / FLOAT_VECTOR_SIZE * FLOAT_VECTOR_SIZE], | ||
| 729 | + tvUbTensor, | ||
| 730 | + (uint64_t)0, | ||
| 731 | + rowNumCurLoop, | ||
| 732 | + AscendC::BinaryRepeatParams( | ||
| 733 | + 1, 1, 0, columnNumRound / FLOAT_BLOCK_SIZE, columnNumRound / FLOAT_BLOCK_SIZE, 1)); | ||
| 734 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 735 | + } | ||
| 736 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 737 | + // *** ls = exp(ls) | ||
| 738 | + AscendC::Exp<float, false>( | ||
| 739 | + lsUbTensor[sUbOffset], | ||
| 740 | + lsUbTensor[sUbOffset], | ||
| 741 | + (uint64_t)0, | ||
| 742 | + CeilDiv(rowNumCurLoop * columnNumRound, FLOAT_VECTOR_SIZE), | ||
| 743 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 744 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 745 | + } | ||
| 746 | + | ||
| 747 | + __aicore__ inline | ||
| 748 | + void CalcLocalRowSum(uint32_t sUbOffset, uint32_t rowNumCurLoopRound, uint32_t columnNum, uint32_t columnNumRound, | ||
| 749 | + uint32_t rowOffset) | ||
| 750 | + { | ||
| 751 | + // *** ll = rowsum(ls32) | ||
| 752 | + if (columnNum == 1024) { | ||
| 753 | + RowsumSPECTILE1024( | ||
| 754 | + lsUbTensor[sUbOffset], | ||
| 755 | + llUbTensor[rowOffset], | ||
| 756 | + tvUbTensor, | ||
| 757 | + rowNumCurLoopRound, | ||
| 758 | + columnNum, | ||
| 759 | + columnNumRound); | ||
| 760 | + } else if (columnNum == 512) { | ||
| 761 | + RowsumSPECTILE512( | ||
| 762 | + lsUbTensor[sUbOffset], | ||
| 763 | + llUbTensor[rowOffset], | ||
| 764 | + tvUbTensor, | ||
| 765 | + rowNumCurLoopRound, | ||
| 766 | + columnNum, | ||
| 767 | + columnNumRound); | ||
| 768 | + } else if (columnNum == 256) { | ||
| 769 | + RowsumSPECTILE256( | ||
| 770 | + lsUbTensor[sUbOffset], | ||
| 771 | + llUbTensor[rowOffset], | ||
| 772 | + tvUbTensor, | ||
| 773 | + rowNumCurLoopRound, | ||
| 774 | + columnNum, | ||
| 775 | + columnNumRound); | ||
| 776 | + } else { | ||
| 777 | + RowsumTAILTILE( | ||
| 778 | + lsUbTensor[sUbOffset], | ||
| 779 | + llUbTensor[rowOffset], | ||
| 780 | + tvUbTensor, | ||
| 781 | + rowNumCurLoopRound, | ||
| 782 | + columnNum, | ||
| 783 | + columnNumRound); | ||
| 784 | + } | ||
| 785 | + } | ||
| 786 | + | ||
| 787 | + __aicore__ inline | ||
| 788 | + void UpdateGlobalRowSum(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t rowNumCurLoopRound, | ||
| 789 | + uint32_t dmUbOffsetCurCycle, uint32_t rowOffset, uint32_t isFirstStackTile) | ||
| 790 | + { | ||
| 791 | + if (isFirstStackTile) { | ||
| 792 | + // *** gl = ll | ||
| 793 | + AscendC::DataCopy( | ||
| 794 | + glUbTensor[rowOffset], | ||
| 795 | + llUbTensor[rowOffset], | ||
| 796 | + AscendC::DataCopyParams(1, rowNumCurLoopRound / FLOAT_BLOCK_SIZE, 0, 0)); | ||
| 797 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 798 | + } else { | ||
| 799 | + SetVecMask(rowNumCurLoop); | ||
| 800 | + // *** gl = dm * gl | ||
| 801 | + AscendC::Mul<float, false>( | ||
| 802 | + glUbTensor[rowOffset], | ||
| 803 | + dmUbTensor[dmUbOffsetCurCycle], | ||
| 804 | + glUbTensor[rowOffset], | ||
| 805 | + (uint64_t)0, | ||
| 806 | + 1, | ||
| 807 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 808 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 809 | + // *** gl = ll + gl | ||
| 810 | + AscendC::Add<float, false>( | ||
| 811 | + glUbTensor[rowOffset], | ||
| 812 | + glUbTensor[rowOffset], | ||
| 813 | + llUbTensor[rowOffset], | ||
| 814 | + (uint64_t)0, | ||
| 815 | + 1, | ||
| 816 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 817 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 818 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 819 | + } | ||
| 820 | + } | ||
| 821 | + | ||
| 822 | + __aicore__ inline | ||
| 823 | + void DownCastP(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t columnNumRound) | ||
| 824 | + { | ||
| 825 | + // *** lp = castfp32to16(ls) | ||
| 826 | + if (std::is_same<ElementOutput, bfloat16_t>::value) { | ||
| 827 | + AscendC::Cast<ElementOutput, float, false>( | ||
| 828 | + lpUbTensor[sUbOffset], | ||
| 829 | + lsUbTensor[sUbOffset], | ||
| 830 | + AscendC::RoundMode::CAST_RINT, | ||
| 831 | + (uint64_t)0, | ||
| 832 | + CeilDiv(rowNumCurLoop * columnNumRound, FLOAT_VECTOR_SIZE), | ||
| 833 | + AscendC::UnaryRepeatParams(1, 1, 4, 8)); | ||
| 834 | + } else { | ||
| 835 | + AscendC::Cast<ElementOutput, float, false>( | ||
| 836 | + lpUbTensor[sUbOffset], | ||
| 837 | + lsUbTensor[sUbOffset], | ||
| 838 | + AscendC::RoundMode::CAST_NONE, | ||
| 839 | + (uint64_t)0, | ||
| 840 | + CeilDiv(rowNumCurLoop * columnNumRound, FLOAT_VECTOR_SIZE), | ||
| 841 | + AscendC::UnaryRepeatParams(1, 1, 4, 8)); | ||
| 842 | + } | ||
| 843 | + } | ||
| 844 | + | ||
| 845 | + __aicore__ inline | ||
| 846 | + void CopyPUbToGm(AscendC::GlobalTensor<ElementOutput> gOutput, uint32_t sUbOffset, uint32_t rowNumCurLoop, | ||
| 847 | + uint32_t columnNumRound, uint32_t columnNumPad) | ||
| 848 | + { | ||
| 849 | + AscendC::DataCopy( | ||
| 850 | + gOutput, | ||
| 851 | + lpUbTensor[sUbOffset], | ||
| 852 | + AscendC::DataCopyParams( | ||
| 853 | + rowNumCurLoop, columnNumRound / BLOCK_SIZE, 0, (columnNumPad - columnNumRound) / BLOCK_SIZE)); | ||
| 854 | + } | ||
| 855 | + | ||
| 856 | + template <bool doTriUMask> | ||
| 857 | + __aicore__ inline | ||
| 858 | + void SubCoreCompute( | ||
| 859 | + AscendC::GlobalTensor<ElementOutput> gOutput, const LayoutOutput &layoutOutput, | ||
| 860 | + uint32_t rowOffset, uint32_t isFirstStackTile, uint32_t isLastNoMaskStackTile, | ||
| 861 | + uint32_t isFirstRowLoop, uint32_t isLastRowLoop, | ||
| 862 | + uint32_t columnNumRound, uint32_t pingpongFlag, | ||
| 863 | + uint32_t curStackTileMod, Arch::CrossCoreFlag softmaxFlag) | ||
| 864 | + { | ||
| 865 | + uint32_t rowNumCurLoop = layoutOutput.shape(0); | ||
| 866 | + uint32_t rowNumCurLoopRound = RoundUp(rowNumCurLoop, FLOAT_BLOCK_SIZE); | ||
| 867 | + uint32_t columnNum = layoutOutput.shape(1); | ||
| 868 | + uint32_t columnNumPad = layoutOutput.stride(0); | ||
| 869 | + uint32_t sUbOffset = pingpongFlag * MAX_UB_S_ELEM_NUM; | ||
| 870 | + uint32_t dmUbOffsetCurCycle = curStackTileMod * MAX_ROW_NUM_SUB_CORE + rowOffset; | ||
| 871 | + | ||
| 872 | + if constexpr (LSE_MODE_ == LseMode::OUT_ONLY) { | ||
| 873 | + // wait for lse from ub to gm | ||
| 874 | + // In lse out-only mode, tv is used in the last stack tile to transport lse | ||
| 875 | + if (isFirstStackTile && isFirstRowLoop) { | ||
| 876 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 877 | + } | ||
| 878 | + } | ||
| 879 | + CalcLocalRowMax(sUbOffset, rowNumCurLoopRound, columnNum, columnNumRound, rowOffset); | ||
| 880 | + UpdateGlobalRowMax( | ||
| 881 | + rowNumCurLoop, rowNumCurLoopRound, | ||
| 882 | + columnNum, columnNumRound, | ||
| 883 | + dmUbOffsetCurCycle, | ||
| 884 | + rowOffset, | ||
| 885 | + isFirstStackTile); | ||
| 886 | + | ||
| 887 | + CalcExp(sUbOffset, rowNumCurLoop, rowNumCurLoopRound, columnNum, columnNumRound, rowOffset); | ||
| 888 | + if constexpr (!doTriUMask) { | ||
| 889 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(pingpongFlag); | ||
| 890 | + } | ||
| 891 | + | ||
| 892 | + DownCastP(sUbOffset, rowNumCurLoop, columnNumRound); | ||
| 893 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(pingpongFlag); | ||
| 894 | + | ||
| 895 | + CalcLocalRowSum(sUbOffset, rowNumCurLoopRound, columnNum, columnNumRound, rowOffset); | ||
| 896 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(pingpongFlag); | ||
| 897 | + | ||
| 898 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(pingpongFlag); | ||
| 899 | + CopyPUbToGm(gOutput, sUbOffset, rowNumCurLoop, columnNumRound, columnNumPad); | ||
| 900 | + if constexpr (!doTriUMask) { | ||
| 901 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(pingpongFlag); | ||
| 902 | + if (isLastNoMaskStackTile && isLastRowLoop) { | ||
| 903 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID0); | ||
| 904 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID0); | ||
| 905 | + } | ||
| 906 | + } else { | ||
| 907 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID0); | ||
| 908 | + } | ||
| 909 | + if (isLastRowLoop) { | ||
| 910 | + NpuArch::Arch::CrossCoreSetFlag<0x2, PIPE_MTE3>(softmaxFlag); | ||
| 911 | + } | ||
| 912 | + UpdateGlobalRowSum( | ||
| 913 | + sUbOffset, rowNumCurLoop, rowNumCurLoopRound, dmUbOffsetCurCycle, rowOffset, isFirstStackTile); | ||
| 914 | + } | ||
| 915 | + | ||
| 916 | + __aicore__ inline | ||
| 917 | + void operator()(AscendC::GlobalTensor<ElementOutput> gOutput, AscendC::GlobalTensor<ElementInput> gInput, | ||
| 918 | + const LayoutOutput &layoutOutput, const LayoutInput &layoutInput, GemmCoord actualBlockShape, | ||
| 919 | + uint32_t isFirstStackTile, uint32_t isLastNoMaskStackTile, | ||
| 920 | + uint32_t qSBlockSize, uint32_t qNBlockSize, uint32_t curStackTileMod, Arch::CrossCoreFlag softmaxFlag) | ||
| 921 | + { | ||
| 922 | + uint32_t rowNum = actualBlockShape.m(); | ||
| 923 | + uint32_t columnNum = actualBlockShape.n(); | ||
| 924 | + uint32_t columnNumRound = RoundUp(columnNum, BLOCK_SIZE); | ||
| 925 | + uint32_t columnNumPad = layoutInput.stride(0); | ||
| 926 | + | ||
| 927 | + uint32_t subBlockIdx = AscendC::GetSubBlockIdx(); | ||
| 928 | + uint32_t subBlockNum = AscendC::GetSubBlockNum(); | ||
| 929 | + | ||
| 930 | + uint32_t qNSplitSubBlock = qNBlockSize / subBlockNum; | ||
| 931 | + uint32_t qNThisSubBlock = (qNBlockSize == 1) ? | ||
| 932 | + 0 : (subBlockIdx == 1) ? (qNBlockSize - qNSplitSubBlock) : qNSplitSubBlock; | ||
| 933 | + uint32_t rowSplitSubBlock = (qNBlockSize == 1) ? | ||
| 934 | + (qSBlockSize / 2) : (qSBlockSize * qNSplitSubBlock); | ||
| 935 | + uint32_t rowActualThisSubBlock = (subBlockIdx == 1) ? (rowNum - rowSplitSubBlock) : rowSplitSubBlock; | ||
| 936 | + uint32_t rowOffsetThisSubBlock = subBlockIdx * rowSplitSubBlock; | ||
| 937 | + uint32_t maxRowNumPerLoop = MAX_UB_S_ELEM_NUM / columnNumRound; | ||
| 938 | + uint32_t rowNumTile = RoundDown(maxRowNumPerLoop, FLOAT_BLOCK_SIZE); | ||
| 939 | + rowNumTile = AscendC::Std::min(rowNumTile, FLOAT_VECTOR_SIZE); | ||
| 940 | + uint32_t rowLoopNum = CeilDiv(rowActualThisSubBlock, rowNumTile); | ||
| 941 | + uint32_t preLoad = 1; | ||
| 942 | + if (rowActualThisSubBlock == 0) { | ||
| 943 | + NpuArch::Arch::CrossCoreSetFlag<0x2, PIPE_MTE3>(softmaxFlag); | ||
| 944 | + return; | ||
| 945 | + } | ||
| 946 | + | ||
| 947 | + for (uint32_t rowLoopIdx = 0; rowLoopIdx < rowLoopNum + preLoad; rowLoopIdx++) { | ||
| 948 | + if (rowLoopIdx < rowLoopNum) { | ||
| 949 | + uint32_t pingpongFlag = rowLoopIdx % 2; | ||
| 950 | + uint32_t rowOffsetCurLoop = rowLoopIdx * rowNumTile; | ||
| 951 | + uint32_t rowOffsetIoGm = rowOffsetCurLoop + rowOffsetThisSubBlock; | ||
| 952 | + uint32_t rowNumCurLoop = (rowLoopIdx == rowLoopNum - 1) ? | ||
| 953 | + (rowActualThisSubBlock - rowOffsetCurLoop) : rowNumTile; | ||
| 954 | + | ||
| 955 | + int64_t offsetInput = layoutInput.GetOffset(MatrixCoord(rowOffsetIoGm, 0)); | ||
| 956 | + auto gInputCurLoop = gInput[offsetInput]; | ||
| 957 | + | ||
| 958 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(pingpongFlag); | ||
| 959 | + CopySGmToUb( | ||
| 960 | + gInputCurLoop, (pingpongFlag * MAX_UB_S_ELEM_NUM), rowNumCurLoop, columnNumRound, columnNumPad); | ||
| 961 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(pingpongFlag); | ||
| 962 | + } | ||
| 963 | + if (rowLoopIdx >= preLoad) { | ||
| 964 | + uint32_t delayedRowLoopIdx = rowLoopIdx - preLoad; | ||
| 965 | + uint32_t pingpongFlag = delayedRowLoopIdx % 2; | ||
| 966 | + uint32_t rowOffsetCurLoop = delayedRowLoopIdx * rowNumTile; | ||
| 967 | + uint32_t rowOffsetIoGm = rowOffsetCurLoop + rowOffsetThisSubBlock; | ||
| 968 | + uint32_t rowNumCurLoop = | ||
| 969 | + (delayedRowLoopIdx == rowLoopNum - 1) ? (rowActualThisSubBlock - rowOffsetCurLoop) : rowNumTile; | ||
| 970 | + | ||
| 971 | + int64_t offsetOutput = layoutOutput.GetOffset(MatrixCoord(rowOffsetIoGm, 0)); | ||
| 972 | + auto gOutputCurLoop = gOutput[offsetOutput]; | ||
| 973 | + auto layoutOutputCurLoop = layoutOutput.GetTileLayout(MatrixCoord(rowNumCurLoop, columnNum)); | ||
| 974 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(pingpongFlag); | ||
| 975 | + ScaleS((pingpongFlag * MAX_UB_S_ELEM_NUM), rowNumCurLoop, columnNumRound); | ||
| 976 | + SubCoreCompute<false>( | ||
| 977 | + gOutputCurLoop, | ||
| 978 | + layoutOutputCurLoop, | ||
| 979 | + rowOffsetCurLoop, | ||
| 980 | + isFirstStackTile, | ||
| 981 | + isLastNoMaskStackTile, | ||
| 982 | + (delayedRowLoopIdx == 0), | ||
| 983 | + (delayedRowLoopIdx == rowLoopNum - 1), | ||
| 984 | + columnNumRound, | ||
| 985 | + pingpongFlag, | ||
| 986 | + curStackTileMod, | ||
| 987 | + softmaxFlag); | ||
| 988 | + } | ||
| 989 | + } | ||
| 990 | + } | ||
| 991 | + | ||
| 992 | + __aicore__ inline | ||
| 993 | + void operator()(AscendC::GlobalTensor<ElementOutput> gOutput, AscendC::GlobalTensor<ElementInput> gInput, | ||
| 994 | + AscendC::GlobalTensor<ElementMask> gMask, const LayoutOutput &layoutOutput, const LayoutInput &layoutInput, | ||
| 995 | + const LayoutInput &layoutMask, GemmCoord actualBlockShape, uint32_t isFirstStackTile, uint32_t qSBlockSize, | ||
| 996 | + uint32_t qNBlockSize, uint32_t curStackTileMod, Arch::CrossCoreFlag qkReady, uint32_t triUp, uint32_t triDown, | ||
| 997 | + uint32_t kvSStartIdx, uint32_t kvSEndIdx) | ||
| 998 | + { | ||
| 999 | + uint32_t rowNum = actualBlockShape.m(); | ||
| 1000 | + uint32_t columnNum = actualBlockShape.n(); | ||
| 1001 | + uint32_t columnNumRound = RoundUp(columnNum, BLOCK_SIZE_IN_BYTE); | ||
| 1002 | + uint32_t columnNumPad = layoutInput.stride(0); | ||
| 1003 | + uint32_t maskStride = layoutMask.stride(0); | ||
| 1004 | + uint32_t subBlockIdx = AscendC::GetSubBlockIdx(); | ||
| 1005 | + uint32_t subBlockNum = AscendC::GetSubBlockNum(); | ||
| 1006 | + | ||
| 1007 | + uint32_t qNSplitSubBlock = qNBlockSize / subBlockNum; | ||
| 1008 | + uint32_t qNThisSubBlock = (qNBlockSize == 1) ? | ||
| 1009 | + 0 : (subBlockIdx == 1) ? (qNBlockSize - qNSplitSubBlock) : qNSplitSubBlock; | ||
| 1010 | + uint32_t rowSplitSubBlock = (qNBlockSize == 1) ? | ||
| 1011 | + (qSBlockSize / 2) : (qSBlockSize * qNSplitSubBlock); | ||
| 1012 | + uint32_t rowActualThisSubBlock = (subBlockIdx == 1) ? | ||
| 1013 | + (rowNum - rowSplitSubBlock) : rowSplitSubBlock; | ||
| 1014 | + uint32_t rowOffsetThisSubBlock = subBlockIdx * rowSplitSubBlock; | ||
| 1015 | + | ||
| 1016 | + uint32_t tokenNumPerHeadThisSubBlock = Min(qSBlockSize, rowActualThisSubBlock); | ||
| 1017 | + uint32_t maskOffsetThisSubBlock = (qNBlockSize == 1) ? | ||
| 1018 | + rowOffsetThisSubBlock : 0; | ||
| 1019 | + | ||
| 1020 | + // calc mask shift in gm | ||
| 1021 | + uint32_t gmOffsetMaskRow; | ||
| 1022 | + uint32_t gmOffsetMaskColumn; | ||
| 1023 | + uint32_t maskColumn; | ||
| 1024 | + uint32_t addMaskUbOffset; | ||
| 1025 | + if (triUp >= kvSStartIdx) { | ||
| 1026 | + uint32_t triUpRoundDown = RoundDown(triUp, BLOCK_SIZE_IN_BYTE); | ||
| 1027 | + gmOffsetMaskRow = triUp - triUpRoundDown; | ||
| 1028 | + gmOffsetMaskColumn = 0; | ||
| 1029 | + maskColumn = kvSEndIdx - triUpRoundDown; | ||
| 1030 | + addMaskUbOffset = triUpRoundDown - kvSStartIdx; | ||
| 1031 | + } else { | ||
| 1032 | + gmOffsetMaskRow = 0; | ||
| 1033 | + gmOffsetMaskColumn = kvSStartIdx - triUp; | ||
| 1034 | + maskColumn = columnNum; | ||
| 1035 | + addMaskUbOffset = 0; | ||
| 1036 | + } | ||
| 1037 | + uint32_t maskColumnRound = RoundUp(maskColumn, BLOCK_SIZE_IN_BYTE); | ||
| 1038 | + | ||
| 1039 | + int64_t offsetMask = | ||
| 1040 | + layoutMask.GetOffset(MatrixCoord(gmOffsetMaskRow + maskOffsetThisSubBlock, gmOffsetMaskColumn)); | ||
| 1041 | + auto gMaskThisSubBlock = gMask[offsetMask]; | ||
| 1042 | + auto layoutMaskThisSubBlock = layoutMask; | ||
| 1043 | + | ||
| 1044 | + uint32_t maxRowNumPerLoop = MAX_UB_S_ELEM_NUM / columnNumRound; | ||
| 1045 | + uint32_t rowNumTile = RoundDown(maxRowNumPerLoop, FLOAT_BLOCK_SIZE); | ||
| 1046 | + rowNumTile = AscendC::Std::min(rowNumTile, FLOAT_VECTOR_SIZE); | ||
| 1047 | + uint32_t rowLoopNum = CeilDiv(rowActualThisSubBlock, rowNumTile); | ||
| 1048 | + uint32_t preLoad = 1; | ||
| 1049 | + | ||
| 1050 | + if (rowActualThisSubBlock == 0) { | ||
| 1051 | + Arch::CrossCoreWaitFlag(qkReady); | ||
| 1052 | + return; | ||
| 1053 | + } | ||
| 1054 | + | ||
| 1055 | + for (uint32_t rowLoopIdx = 0; rowLoopIdx < rowLoopNum + preLoad; rowLoopIdx++) { | ||
| 1056 | + if (rowLoopIdx < rowLoopNum) { | ||
| 1057 | + uint32_t pingpongFlag = rowLoopIdx % 2; | ||
| 1058 | + uint32_t rowOffsetCurLoop = rowLoopIdx * rowNumTile; | ||
| 1059 | + uint32_t rowOffsetIoGm = rowOffsetCurLoop + rowOffsetThisSubBlock; | ||
| 1060 | + uint32_t rowNumCurLoop = (rowLoopIdx == rowLoopNum - 1) ? | ||
| 1061 | + (rowActualThisSubBlock - rowOffsetCurLoop) : rowNumTile; | ||
| 1062 | + // loop 0 mask load before cross core sync | ||
| 1063 | + if (rowLoopIdx == 0) { | ||
| 1064 | + // the token idx of the start token of the prologue part | ||
| 1065 | + uint32_t proTokenIdx = rowOffsetCurLoop % tokenNumPerHeadThisSubBlock; | ||
| 1066 | + // the token num of the prologue part | ||
| 1067 | + uint32_t proTokenNum = | ||
| 1068 | + Min(rowNumCurLoop, (tokenNumPerHeadThisSubBlock - proTokenIdx)) % tokenNumPerHeadThisSubBlock; | ||
| 1069 | + // the token num of the epilogue part | ||
| 1070 | + uint32_t integralHeadNum = (rowNumCurLoop - proTokenNum) / tokenNumPerHeadThisSubBlock; | ||
| 1071 | + // the number of integral heads within a cycle | ||
| 1072 | + uint32_t epiTokenNum = rowNumCurLoop - proTokenNum - integralHeadNum * tokenNumPerHeadThisSubBlock; | ||
| 1073 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID0); | ||
| 1074 | + CopyMaskGmToUb( | ||
| 1075 | + gMaskThisSubBlock, | ||
| 1076 | + maskColumn, maskColumnRound, maskStride, | ||
| 1077 | + tokenNumPerHeadThisSubBlock, | ||
| 1078 | + proTokenIdx, proTokenNum, integralHeadNum, epiTokenNum); | ||
| 1079 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID2); | ||
| 1080 | + Arch::CrossCoreWaitFlag(qkReady); | ||
| 1081 | + } | ||
| 1082 | + int64_t offsetInput = layoutInput.GetOffset(MatrixCoord(rowOffsetIoGm, 0)); | ||
| 1083 | + auto gInputCurLoop = gInput[offsetInput]; | ||
| 1084 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(pingpongFlag); | ||
| 1085 | + CopySGmToUb( | ||
| 1086 | + gInputCurLoop, (pingpongFlag * MAX_UB_S_ELEM_NUM), rowNumCurLoop, columnNumRound, columnNumPad); | ||
| 1087 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(pingpongFlag); | ||
| 1088 | + } | ||
| 1089 | + if (rowLoopIdx >= preLoad) { | ||
| 1090 | + uint32_t delayedRowLoopIdx = rowLoopIdx - preLoad; | ||
| 1091 | + uint32_t pingpongFlag = delayedRowLoopIdx % 2; | ||
| 1092 | + uint32_t rowOffsetCurLoop = delayedRowLoopIdx * rowNumTile; | ||
| 1093 | + uint32_t rowNumCurLoop = (delayedRowLoopIdx == rowLoopNum - 1) ? | ||
| 1094 | + (rowActualThisSubBlock - rowOffsetCurLoop) : rowNumTile; | ||
| 1095 | + | ||
| 1096 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID2); | ||
| 1097 | + UpCastMask<half, ElementMask>(maskUbTensor16, maskUbTensor, rowNumCurLoop, columnNumRound); | ||
| 1098 | + UpCastMask<float, half>(maskUbTensor32, maskUbTensor16, rowNumCurLoop, columnNumRound); | ||
| 1099 | + | ||
| 1100 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(pingpongFlag); | ||
| 1101 | + ScaleS((pingpongFlag * MAX_UB_S_ELEM_NUM), rowNumCurLoop, columnNumRound); | ||
| 1102 | + ApplyMask( | ||
| 1103 | + (pingpongFlag * MAX_UB_S_ELEM_NUM), | ||
| 1104 | + rowNumCurLoop, columnNumRound, | ||
| 1105 | + maskColumnRound, addMaskUbOffset); | ||
| 1106 | + // next loop mask load | ||
| 1107 | + if (rowLoopIdx < rowLoopNum) { | ||
| 1108 | + uint32_t rowOffsetCurLoop = rowLoopIdx * rowNumTile; | ||
| 1109 | + uint32_t rowNumCurLoop = | ||
| 1110 | + (rowLoopIdx == rowLoopNum - 1) ? (rowActualThisSubBlock - rowOffsetCurLoop) : rowNumTile; | ||
| 1111 | + // the token idx of the start token of the prologue part | ||
| 1112 | + uint32_t proTokenIdx = rowOffsetCurLoop % tokenNumPerHeadThisSubBlock; | ||
| 1113 | + // the token num of the prologue part | ||
| 1114 | + uint32_t proTokenNum = | ||
| 1115 | + Min(rowNumCurLoop, (tokenNumPerHeadThisSubBlock - proTokenIdx)) % tokenNumPerHeadThisSubBlock; | ||
| 1116 | + // the number of integral heads within a cycle | ||
| 1117 | + uint32_t integralHeadNum = (rowNumCurLoop - proTokenNum) / tokenNumPerHeadThisSubBlock; | ||
| 1118 | + // the token num of the epilogue part | ||
| 1119 | + uint32_t epiTokenNum = rowNumCurLoop - proTokenNum - integralHeadNum * tokenNumPerHeadThisSubBlock; | ||
| 1120 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID0); | ||
| 1121 | + CopyMaskGmToUb( | ||
| 1122 | + gMaskThisSubBlock, | ||
| 1123 | + maskColumn, maskColumnRound, maskStride, | ||
| 1124 | + tokenNumPerHeadThisSubBlock, | ||
| 1125 | + proTokenIdx, proTokenNum, integralHeadNum, epiTokenNum); | ||
| 1126 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID2); | ||
| 1127 | + } | ||
| 1128 | + // online softmax vectorized compute | ||
| 1129 | + uint32_t rowOffsetIoGm = rowOffsetCurLoop + rowOffsetThisSubBlock; | ||
| 1130 | + int64_t offsetOutput = layoutOutput.GetOffset(MatrixCoord(rowOffsetIoGm, 0)); | ||
| 1131 | + auto gOutputCurLoop = gOutput[offsetOutput]; | ||
| 1132 | + auto layoutOutputCurLoop = layoutOutput.GetTileLayout(MatrixCoord(rowNumCurLoop, columnNum)); | ||
| 1133 | + SubCoreCompute<true>( | ||
| 1134 | + gOutputCurLoop, | ||
| 1135 | + layoutOutputCurLoop, | ||
| 1136 | + rowOffsetCurLoop, | ||
| 1137 | + isFirstStackTile, | ||
| 1138 | + 0, | ||
| 1139 | + (delayedRowLoopIdx == 0), | ||
| 1140 | + (delayedRowLoopIdx == rowLoopNum - 1), | ||
| 1141 | + columnNumRound, | ||
| 1142 | + pingpongFlag, | ||
| 1143 | + curStackTileMod); | ||
| 1144 | + } | ||
| 1145 | + } | ||
| 1146 | + } | ||
| 1147 | + | ||
| 1148 | +private: | ||
| 1149 | + float scaleValue; | ||
| 1150 | + AscendC::LocalTensor<float> lsUbTensor; | ||
| 1151 | + AscendC::LocalTensor<ElementOutput> lpUbTensor; | ||
| 1152 | + AscendC::LocalTensor<ElementMask> maskUbTensor; | ||
| 1153 | + AscendC::LocalTensor<half> maskUbTensor16; | ||
| 1154 | + AscendC::LocalTensor<float> maskUbTensor32; | ||
| 1155 | + AscendC::LocalTensor<float> lmUbTensor; | ||
| 1156 | + AscendC::LocalTensor<float> hmUbTensor; | ||
| 1157 | + AscendC::LocalTensor<float> gmUbTensor; | ||
| 1158 | + AscendC::LocalTensor<float> dmUbTensor; | ||
| 1159 | + AscendC::LocalTensor<float> llUbTensor; | ||
| 1160 | + AscendC::LocalTensor<float> tvUbTensor; | ||
| 1161 | + AscendC::LocalTensor<float> glUbTensor; | ||
| 1162 | +}; | ||
| 1163 | +} | ||
| 1164 | + | ||
| 1165 | + | ||
| @@ -0,0 +1,528 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +using AscendC::printf; | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +namespace NpuArch::Epilogue::Block { | ||
| 26 | + | ||
| 27 | +template <typename DefaultType> | ||
| 28 | +struct ElementPTmpTypeLookup { | ||
| 29 | + using type = DefaultType; | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +template <> | ||
| 33 | +struct ElementPTmpTypeLookup<float8_e4m3_t> { | ||
| 34 | + using type = half; | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +enum class KvBaseTileRegSplitStages { | ||
| 38 | + ONE, | ||
| 39 | + TWO | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +template < | ||
| 43 | + class OutputType_, | ||
| 44 | + class LayoutS_> | ||
| 45 | +class BlockEpilogue< | ||
| 46 | + EpilogueOnlineSoftmaxBsa, | ||
| 47 | + OutputType_, | ||
| 48 | + Gemm::GemmType<half, LayoutS_>> | ||
| 49 | +{ | ||
| 50 | +public: | ||
| 51 | + using DispatchPolicy = EpilogueOnlineSoftmaxBsa; | ||
| 52 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 53 | + using ElementOutput = typename OutputType_::Element; | ||
| 54 | + using ElementOutputTmp = typename ElementPTmpTypeLookup<ElementOutput>::type; | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + using ElementInput = half; | ||
| 58 | + using LayoutOutput = typename OutputType_::Layout; | ||
| 59 | + using LayoutInput = LayoutS_; | ||
| 60 | + | ||
| 61 | + static constexpr uint32_t BLOCK_SIZE_IN_BYTE = 32; | ||
| 62 | + static constexpr uint32_t REPEAT_SIZE_IN_BYTE = 256; | ||
| 63 | + static constexpr uint32_t FLOAT_BLOCK_SIZE = 8; | ||
| 64 | + static constexpr uint32_t FP8_BLOCK_SIZE = 32; | ||
| 65 | + static constexpr uint32_t FLOAT_VECTOR_SIZE = 64; | ||
| 66 | + static constexpr uint32_t HALF_VECTOR_SIZE = 128; | ||
| 67 | + static constexpr uint32_t BLOCK_SIZE = 16; | ||
| 68 | + static constexpr uint32_t UB_UINT8_VECTOR_SIZE = 1024; | ||
| 69 | + static constexpr uint32_t UB_UINT8_BLOCK_SIZE = 32768; | ||
| 70 | + static constexpr uint32_t VECTOR_SIZE = 128; | ||
| 71 | + static constexpr uint32_t MAX_UB_S_ELEM_NUM = 32768; | ||
| 72 | + static constexpr uint32_t DM_UB_GLOBAL_ELEM_NUM = 64 * 2; //! 2* for 11 22 ... 32,32 | ||
| 73 | + static constexpr uint32_t ELE_NUM_PER_C0 = 16; | ||
| 74 | + | ||
| 75 | + static constexpr uint32_t REDUCE_UB_SIZE = 1024; | ||
| 76 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_32 = 32; | ||
| 77 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_8 = 8; | ||
| 78 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_4 = 4; | ||
| 79 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_2 = 2; | ||
| 80 | + static constexpr uint32_t MAX_ROW_NUM_SUB_CORE = 256; | ||
| 81 | + static constexpr int64_t UB_FLOAT_LINE_SIZE = 64; | ||
| 82 | + | ||
| 83 | + static constexpr uint32_t SPLIT_COL_IDX_2 = 2; | ||
| 84 | + static constexpr uint32_t SPLIT_COL_IDX_3 = 3; | ||
| 85 | + static constexpr ElementInput MIN_VALUE = -65504.0f; | ||
| 86 | + static constexpr uint32_t FP8_REP_SIZE = 128 *2; | ||
| 87 | + static constexpr uint32_t HALF_REP_SIZE = 128; | ||
| 88 | + static constexpr uint32_t FLOAT_REP_SIZE = 64; | ||
| 89 | + static constexpr uint32_t BLOCK_REP_SIZE = 8; | ||
| 90 | + static constexpr uint32_t REPEAT_STRIDE = 1; | ||
| 91 | + static constexpr uint32_t C0_NUM_PER_FRACTAL = 16; | ||
| 92 | + static constexpr uint32_t SM_ROW_MAX_ELEM_NUM = 64; | ||
| 93 | + static constexpr uint32_t SM_COL_MAX_ELEM_NUM = 512; | ||
| 94 | + static constexpr uint32_t SM_VREG_SIZE = 256 / sizeof(ElementInput); | ||
| 95 | + static constexpr uint32_t QUANT_MODE1_SCALE_BYTES = 1024; | ||
| 96 | + | ||
| 97 | + __aicore__ inline | ||
| 98 | + BlockEpilogue(Arch::Resource<ArchTag> &resource, float scaleValue_, uint32_t blockSizeY_ = 128) | ||
| 99 | + { | ||
| 100 | + // Allocate UB space | ||
| 101 | + constexpr uint32_t LS_UB_TENSOR_OFFSET = 0; | ||
| 102 | + constexpr uint32_t LP_UB_TENSOR_OFFSET = LS_UB_TENSOR_OFFSET; | ||
| 103 | + | ||
| 104 | + constexpr uint32_t LM_UB_TENSOR_OFFSET = 7 * UB_UINT8_BLOCK_SIZE; | ||
| 105 | + constexpr uint32_t GM_UB_TENSOR_OFFSET = LM_UB_TENSOR_OFFSET + 128 * sizeof(float); | ||
| 106 | + constexpr uint32_t DM_UB_TENSOR_OFFSET = GM_UB_TENSOR_OFFSET + 128 * sizeof(float); | ||
| 107 | + constexpr uint32_t LL_UB_TENSOR_OFFSET = DM_UB_TENSOR_OFFSET + 3 * 128 * sizeof(float); | ||
| 108 | + constexpr uint32_t GL_UB_TENSOR_OFFSET = LL_UB_TENSOR_OFFSET + 128 * sizeof(float); | ||
| 109 | + constexpr uint32_t SCALE_UB_TENSOR_OFFSET = GL_UB_TENSOR_OFFSET + 128 * sizeof(float); | ||
| 110 | + | ||
| 111 | + subBlockIdx_ = AscendC::GetSubBlockIdx(); | ||
| 112 | + | ||
| 113 | + scaleValue = scaleValue_; | ||
| 114 | + blockSizeK = blockSizeY_; | ||
| 115 | + lsUbTensor = resource.ubBuf.template GetBufferByByte<ElementInput>(LS_UB_TENSOR_OFFSET); | ||
| 116 | + lpUbTensor = resource.ubBuf.template GetBufferByByte<uint16_t>(LP_UB_TENSOR_OFFSET); | ||
| 117 | + gmUbTensor = resource.ubBuf.template GetBufferByByte<ElementInput>(GM_UB_TENSOR_OFFSET); | ||
| 118 | + glUbTensor = resource.ubBuf.template GetBufferByByte<float>(GL_UB_TENSOR_OFFSET); | ||
| 119 | + dmUbTensor = resource.ubBuf.template GetBufferByByte<float>(DM_UB_TENSOR_OFFSET); | ||
| 120 | + lmUbTensor = resource.ubBuf.template GetBufferByByte<ElementInput>(LM_UB_TENSOR_OFFSET); | ||
| 121 | + llUbTensor = resource.ubBuf.template GetBufferByByte<ElementInput>(LL_UB_TENSOR_OFFSET); | ||
| 122 | + scaleTensor = resource.ubBuf.template GetBufferByByte<ElementInput>(SCALE_UB_TENSOR_OFFSET); | ||
| 123 | + tmpTensor = resource.ubBuf.template GetBufferByByte<uint8_t>(LM_UB_TENSOR_OFFSET + 4096U); | ||
| 124 | + AscendC::SetFlag<AscendC::HardEvent::V_S>(EVENT_ID0); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + __aicore__ inline | ||
| 128 | + ~BlockEpilogue() | ||
| 129 | + { | ||
| 130 | + AscendC::WaitFlag<AscendC::HardEvent::V_S>(EVENT_ID0); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + template <class TensorDst, class TensorSrc> | ||
| 134 | + __aicore__ inline | ||
| 135 | + void CopyPUbToPL1(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint32_t m, uint32_t nRound, uint32_t actRowsCube) | ||
| 136 | + { | ||
| 137 | + constexpr uint32_t BlockElements = BLOCK_SIZE_IN_BYTE / sizeof(ElementOutput); | ||
| 138 | + if constexpr (sizeof(ElementOutput) == 2) { | ||
| 139 | + const uint32_t blockCount = tla::get<1, 1>(srcTensor.shape()); | ||
| 140 | + const uint32_t blockLen = tla::get<0, 0>(srcTensor.shape()) * tla::get<0, 1>(srcTensor.shape()); | ||
| 141 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 142 | + constexpr int32_t C0_SIZE = BLOCK_SIZE_IN_BYTE / sizeof(typename TensorDst::Element); | ||
| 143 | + AscendC::DataCopyParams repeatParams; | ||
| 144 | + | ||
| 145 | + repeatParams.blockCount = blockCount; | ||
| 146 | + repeatParams.blockLen = m; | ||
| 147 | + repeatParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / C0_SIZE - m; | ||
| 148 | + repeatParams.dstStride = tla::get<1, 1>(dstTensor.stride()) / C0_SIZE - m; | ||
| 149 | + | ||
| 150 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 151 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 152 | + | ||
| 153 | + AscendC::DataCopy(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], repeatParams); | ||
| 154 | + } else if constexpr (sizeof(ElementOutput) == 1) { // dn 2 Zn | ||
| 155 | + auto mRound = RoundUp(m, BlockElements); | ||
| 156 | + auto dstOffset = subBlockIdx_ == 0 ? 0 : (actRowsCube - m) * nRound; | ||
| 157 | + AscendC::DataCopy(dstTensor.data()[dstOffset], srcTensor.data(), mRound * nRound); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 162 | + __aicore__ inline | ||
| 163 | + void SetCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 164 | + { | ||
| 165 | + if constexpr (MODE == 4U) { | ||
| 166 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlag); | ||
| 167 | + } | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 171 | + __aicore__ inline | ||
| 172 | + void WaitCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 173 | + { | ||
| 174 | + if constexpr (MODE == 4U) { | ||
| 175 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlag); | ||
| 176 | + } | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + template <class TensorP> | ||
| 180 | + __aicore__ inline | ||
| 181 | + void operator()(TensorP &l1PTensorTla, GemmCoord actualBlockShape, | ||
| 182 | + uint32_t isFirstKvSTile, uint32_t ubSBufId, uint32_t l1PBufId, | ||
| 183 | + Arch::CrossCoreFlag mm1ToSmFlag, Arch::CrossCoreFlag smToMm2Flag){ | ||
| 184 | + | ||
| 185 | + struct EmptyTensor {}; | ||
| 186 | + EmptyTensor dummyQS; | ||
| 187 | + EmptyTensor dummyKS; | ||
| 188 | + operator()<0>(l1PTensorTla, dummyQS, dummyKS, | ||
| 189 | + actualBlockShape, | ||
| 190 | + isFirstKvSTile, ubSBufId, l1PBufId, | ||
| 191 | + mm1ToSmFlag, smToMm2Flag, AscendC::GlobalTensor<int32_t>()); | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + template <int quant_mode, class TensorP, class TensorQS, class TensorKS, typename ElementIndex> | ||
| 195 | + __aicore__ inline | ||
| 196 | + void operator()(TensorP &l1PTensorTla, TensorQS &gmQSTensorTla, TensorKS &gmKSTensorTla, | ||
| 197 | + GemmCoord actualBlockShape, | ||
| 198 | + uint32_t isFirstKvSTile, uint32_t ubSBufId, uint32_t l1PBufId, | ||
| 199 | + Arch::CrossCoreFlag mm1ToSmFlag, Arch::CrossCoreFlag smToMm2Flag, | ||
| 200 | + const AscendC::GlobalTensor<ElementIndex>& sparseIndex) | ||
| 201 | + { | ||
| 202 | + static_assert(quant_mode == 0 || quant_mode == 1); | ||
| 203 | + constexpr int16_t vlSize = static_cast<int16_t>(AscendC::GetVecLen() / sizeof(ElementInput)); | ||
| 204 | + uint32_t m; | ||
| 205 | + uint16_t mRound; | ||
| 206 | + uint32_t mCopyOffset = 0; | ||
| 207 | + const uint32_t mTot = actualBlockShape.m(); | ||
| 208 | + if constexpr (quant_mode == 0) { | ||
| 209 | + mCopyOffset = RoundUp(actualBlockShape.m(), 8) / 2; | ||
| 210 | + m = actualBlockShape.m() < mCopyOffset ? actualBlockShape.m() : mCopyOffset; | ||
| 211 | + m = subBlockIdx_ == 0 ? m : actualBlockShape.m() - m; | ||
| 212 | + mRound = RoundUp(m, C0_NUM_PER_FRACTAL); | ||
| 213 | + } else { | ||
| 214 | + if (mTot <= FP8_BLOCK_SIZE) { | ||
| 215 | + m = (subBlockIdx_ == 0) ? mTot : 0; | ||
| 216 | + } else { | ||
| 217 | + uint32_t mhalf = (mTot + 1) / 2; | ||
| 218 | + uint32_t mAlign = (mhalf > FP8_BLOCK_SIZE) ? RoundUp(mhalf, FP8_BLOCK_SIZE) : FP8_BLOCK_SIZE; | ||
| 219 | + m = (subBlockIdx_ == 0) ? mAlign : (mTot - mAlign); | ||
| 220 | + mCopyOffset = (subBlockIdx_ == 0) ? 0 : mAlign; | ||
| 221 | + } | ||
| 222 | + mRound = RoundUp(m, FP8_BLOCK_SIZE); | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + if (m == 0) { | ||
| 226 | + WaitCrossCoreSync<4, PIPE_V>(mm1ToSmFlag); | ||
| 227 | + SetCrossCoreSync<4, PIPE_V>(mm1ToSmFlag); | ||
| 228 | + WaitCrossCoreSync<4, PIPE_MTE3>(smToMm2Flag); | ||
| 229 | + SetCrossCoreSync<4, PIPE_MTE3>(smToMm2Flag); | ||
| 230 | + return; | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | + uint32_t n = actualBlockShape.n(); | ||
| 234 | + uint16_t nRound = RoundUp(n, 16); | ||
| 235 | + auto paddingSize = (nRound - n) * FP8_BLOCK_SIZE; | ||
| 236 | + | ||
| 237 | + // wait QK Fixpipe finsh | ||
| 238 | + WaitCrossCoreSync<4, PIPE_V>(mm1ToSmFlag); | ||
| 239 | + constexpr uint32_t QUANT_BLOCK_SIZE = 64; | ||
| 240 | + if constexpr (quant_mode == 1){ | ||
| 241 | + auto qlayout = gmQSTensorTla.layout(); | ||
| 242 | + auto klayout = gmKSTensorTla.layout(); | ||
| 243 | + uint32_t blockNum = AscendC::CeilDivision(n, blockSizeK); | ||
| 244 | + uint32_t subNLoops = AscendC::CeilDivision(blockSizeK, QUANT_BLOCK_SIZE); | ||
| 245 | + | ||
| 246 | + auto qOffset = qlayout(tla::MakeCoord(mTot <= QUANT_BLOCK_SIZE ? 0 : subBlockIdx_, static_cast<uint32_t>(0))); | ||
| 247 | + float qscale = gmQSTensorTla.data().GetValue(qOffset); | ||
| 248 | + AscendC::WaitFlag<AscendC::HardEvent::V_S>(EVENT_ID0); | ||
| 249 | + for(uint32_t i = 0; i < blockNum; i++){ | ||
| 250 | + uint32_t index = sparseIndex.GetValue(i); | ||
| 251 | + auto jloops = n - i * blockSizeK <= QUANT_BLOCK_SIZE ? 1 : subNLoops; | ||
| 252 | + for(uint32_t j = 0; j < jloops; j++) { | ||
| 253 | + float ks = gmKSTensorTla.data().GetValue(index * subNLoops + j); | ||
| 254 | + auto s = ks * qscale; // scaleValue on fixpipe | ||
| 255 | + scaleTensor.SetValue(i*subNLoops + j, static_cast<ElementInput>(s)); | ||
| 256 | + } | ||
| 257 | + } | ||
| 258 | + AscendC::SetFlag<AscendC::HardEvent::S_V>(EVENT_ID0); | ||
| 259 | + AscendC::WaitFlag<AscendC::HardEvent::S_V>(EVENT_ID0); | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + ElementInput minValue = -60000.0f; | ||
| 263 | + if (isFirstKvSTile) { | ||
| 264 | + AscendC::Duplicate(gmUbTensor, minValue, 256); // max | ||
| 265 | + AscendC::Duplicate(glUbTensor, 0.0f, 128); // sum | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + if (unlikely(n < nRound)) { | ||
| 269 | + AscendC::Duplicate(lsUbTensor[ubSBufId * MAX_UB_S_ELEM_NUM + n * FP8_BLOCK_SIZE], minValue, paddingSize); | ||
| 270 | + if (mRound == 64) {AscendC::Duplicate(lsUbTensor[ubSBufId * MAX_UB_S_ELEM_NUM + (n + nRound) * FP8_BLOCK_SIZE], minValue, paddingSize);} | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 274 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(ubSBufId + 2);// alloc P | ||
| 275 | + auto lpUbOutTensor = lpUbTensor[ubSBufId * MAX_UB_S_ELEM_NUM].template ReinterpretCast<float8_e4m3_t>(); | ||
| 276 | + DnSoftmaxQuantBlock<float8_e4m3_t, half, FP8_BLOCK_SIZE, true>(lpUbOutTensor, lsUbTensor[ubSBufId * MAX_UB_S_ELEM_NUM], | ||
| 277 | + gmUbTensor, gmUbTensor, | ||
| 278 | + dmUbTensor[l1PBufId * DM_UB_GLOBAL_ELEM_NUM], | ||
| 279 | + glUbTensor, glUbTensor, scaleTensor, | ||
| 280 | + tmpTensor, nRound); | ||
| 281 | + | ||
| 282 | + if (mRound == 64) { | ||
| 283 | + DnSoftmaxQuantBlock<float8_e4m3_t, half, FP8_BLOCK_SIZE, true>(lpUbOutTensor[FP8_BLOCK_SIZE * nRound], lsUbTensor[ubSBufId * MAX_UB_S_ELEM_NUM + FP8_BLOCK_SIZE * nRound], | ||
| 284 | + gmUbTensor[128], gmUbTensor[128], | ||
| 285 | + dmUbTensor[l1PBufId * DM_UB_GLOBAL_ELEM_NUM + 64], | ||
| 286 | + glUbTensor[64], glUbTensor[64], scaleTensor, | ||
| 287 | + tmpTensor, nRound); | ||
| 288 | + } | ||
| 289 | + if constexpr (quant_mode == 1) { | ||
| 290 | + AscendC::SetFlag<AscendC::HardEvent::V_S>(EVENT_ID0); | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + if (unlikely(n < nRound)) { | ||
| 294 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 295 | + auto lpPad = lpUbOutTensor[n * FP8_BLOCK_SIZE].template ReinterpretCast<int8_t>(); | ||
| 296 | + AscendC::Duplicate(lpPad, (int8_t)0, paddingSize); | ||
| 297 | + if (mRound == 64) {AscendC::Duplicate(lpPad[nRound * FP8_BLOCK_SIZE], (int8_t)0, paddingSize);} | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(ubSBufId); // P enque | ||
| 301 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(ubSBufId); // P deque | ||
| 302 | + | ||
| 303 | + auto ubPLayoutTla = tla::MakeLayout<ElementOutput, LayoutOutput>(mRound, nRound); | ||
| 304 | + | ||
| 305 | + auto ubPTensorTla = tla::MakeTensor(lpUbOutTensor, ubPLayoutTla, Arch::PositionUB{}); | ||
| 306 | + auto ubPTensorTlaTile = GetTile(ubPTensorTla, tla::MakeCoord(0, 0), tla::MakeShape(m, n)); | ||
| 307 | + auto l1PTensorTlaTile = GetTile(l1PTensorTla, tla::MakeCoord(subBlockIdx_ * mCopyOffset, 0), tla::MakeShape(m, n)); | ||
| 308 | + WaitCrossCoreSync<4, PIPE_MTE3>(smToMm2Flag); | ||
| 309 | + | ||
| 310 | + CopyPUbToPL1(l1PTensorTlaTile, ubPTensorTlaTile, m, nRound, actualBlockShape.m()); | ||
| 311 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(ubSBufId + 2); //Free P | ||
| 312 | + SetCrossCoreSync<4, PIPE_MTE3>(mm1ToSmFlag); | ||
| 313 | + SetCrossCoreSync<4, PIPE_MTE3>(smToMm2Flag); | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | +private: | ||
| 317 | + float scaleValue; | ||
| 318 | + AscendC::LocalTensor<ElementInput> lsUbTensor; | ||
| 319 | + AscendC::LocalTensor<uint16_t> lpUbTensor; | ||
| 320 | + AscendC::LocalTensor<ElementInput> gmUbTensor; | ||
| 321 | + AscendC::LocalTensor<float> glUbTensor; | ||
| 322 | + AscendC::LocalTensor<float> dmUbTensor; | ||
| 323 | + AscendC::LocalTensor<ElementInput> lmUbTensor; | ||
| 324 | + AscendC::LocalTensor<ElementInput> llUbTensor; | ||
| 325 | + AscendC::LocalTensor<ElementInput> scaleTensor; | ||
| 326 | + | ||
| 327 | + AscendC::LocalTensor<uint8_t> tmpTensor; | ||
| 328 | + uint32_t subBlockIdx_, blockSizeK; | ||
| 329 | + | ||
| 330 | + template <typename T2, typename T, uint16_t m = 32, bool DEQ = true, uint16_t MAX_COLS = 256, uint16_t DEQ_BLK = 64> | ||
| 331 | + __aicore__ inline void DnSoftmaxQuantBlock( | ||
| 332 | + const AscendC::LocalTensor<T2>& dstTensor, | ||
| 333 | + const AscendC::LocalTensor<T>& srcDnTensor, | ||
| 334 | + const AscendC::LocalTensor<T>& maxTensor, | ||
| 335 | + const AscendC::LocalTensor<T>& inMaxTensor, | ||
| 336 | + const AscendC::LocalTensor<float>& expMaxTensor, | ||
| 337 | + const AscendC::LocalTensor<float>& expSumTensor, | ||
| 338 | + const AscendC::LocalTensor<float>& inSumTensor, | ||
| 339 | + const AscendC::LocalTensor<T>& scaleTensor, | ||
| 340 | + const AscendC::LocalTensor<uint8_t>& tmpTensor, | ||
| 341 | + const uint32_t n) | ||
| 342 | + { | ||
| 343 | + using namespace AscendC::MicroAPI; | ||
| 344 | + | ||
| 345 | + constexpr static CastTrait castTraitFp32Zero = { | ||
| 346 | + RegLayout::ZERO, SatMode::UNKNOWN, MaskMergeMode::ZEROING, AscendC::RoundMode::UNKNOWN, | ||
| 347 | + }; | ||
| 348 | + constexpr static CastTrait castTraitFp32One = { | ||
| 349 | + RegLayout::ONE, SatMode::UNKNOWN, MaskMergeMode::ZEROING, AscendC::RoundMode::UNKNOWN, | ||
| 350 | + }; | ||
| 351 | + | ||
| 352 | + __ubuf__ T* srcUb = (__ubuf__ T*)srcDnTensor.GetPhyAddr(); | ||
| 353 | + __ubuf__ T2* dstUb = (__ubuf__ T2*)dstTensor.GetPhyAddr(); | ||
| 354 | + | ||
| 355 | + __ubuf__ T* inMaxUb = (__ubuf__ T*)inMaxTensor.GetPhyAddr(); | ||
| 356 | + __ubuf__ T* maxUb = (__ubuf__ T*)maxTensor.GetPhyAddr(); | ||
| 357 | + | ||
| 358 | + __ubuf__ float* expMaxUb = (__ubuf__ float*)expMaxTensor.GetPhyAddr(); | ||
| 359 | + __ubuf__ float* inSumUb = (__ubuf__ float*)inSumTensor.GetPhyAddr(); | ||
| 360 | + __ubuf__ float* expSumUb = (__ubuf__ float*)expSumTensor.GetPhyAddr(); | ||
| 361 | + | ||
| 362 | + __ubuf__ float* tmpMaxUbStart = (__ubuf__ float*)tmpTensor.GetPhyAddr(); | ||
| 363 | + __ubuf__ T* scaleUb = (__ubuf__ T*) scaleTensor.GetPhyAddr(); | ||
| 364 | + | ||
| 365 | + T minValue = -65504.0f; | ||
| 366 | + constexpr uint16_t VL = 256; | ||
| 367 | + constexpr uint16_t UNROLL = 4; | ||
| 368 | + constexpr uint16_t VL_ELE_B16 = 128; | ||
| 369 | + constexpr uint16_t R = VL / sizeof(T) / m; // R = 4 | ||
| 370 | + | ||
| 371 | + __VEC_SCOPE__ | ||
| 372 | + { | ||
| 373 | + RegTensor<T> vregMax0, vregMax1, vregMax2, vregMax3; | ||
| 374 | + RegTensor<T> vregAcc0, vregAcc1, vregAcc2, vregAcc3; | ||
| 375 | + RegTensor<T> vregSrc0, vregSrc1, vregSrc2, vregSrc3; | ||
| 376 | + RegTensor<T> vregScale; | ||
| 377 | + RegTensor<int8_t> vregZero0, vregZero1, vregFp8High0, vregFp8High1; | ||
| 378 | + RegTensor<T2> vregDst0, vregDst1; | ||
| 379 | + | ||
| 380 | + RegTensor<T> vregInMax, vregExpMax16; | ||
| 381 | + RegTensor<T> vregGlobalMax; | ||
| 382 | + RegTensor<float> vregExpMax32; | ||
| 383 | + RegTensor<float> vregInExpSum; | ||
| 384 | + RegTensor<float> vregExpSum32; | ||
| 385 | + RegTensor<T> vregTmp0, vregTmp1; | ||
| 386 | + | ||
| 387 | + RegTensor<T> vregLocalReduce; | ||
| 388 | + | ||
| 389 | + MaskReg pregAll = CreateMask<T, MaskPattern::ALL>(); | ||
| 390 | + MaskReg pregAll32 = CreateMask<float, MaskPattern::ALL>(); | ||
| 391 | + uint32_t tmpM = m; | ||
| 392 | + | ||
| 393 | + MaskReg pregM = UpdateMask<T>(tmpM); | ||
| 394 | + MaskReg preg64 = CreateMask<T, MaskPattern::VL64>(); | ||
| 395 | + MaskReg preg32 = CreateMask<T, MaskPattern::VL32>(); | ||
| 396 | + MaskReg pregAllB8 = CreateMask<T2, MaskPattern::ALL>(); | ||
| 397 | + MaskReg pregHalfFp8 = CreateMask<T2, MaskPattern::VL128>(); | ||
| 398 | + | ||
| 399 | + Duplicate<T, T>(vregMax0, minValue); | ||
| 400 | + Duplicate<T, T>(vregMax1, minValue); | ||
| 401 | + Duplicate<T, T>(vregMax2, minValue); | ||
| 402 | + Duplicate<T, T>(vregMax3, minValue); | ||
| 403 | + | ||
| 404 | + DataCopy<T, LoadDist::DIST_NORM>(vregInMax, inMaxUb); // 1111 2222 3333 ... 32,32,32,32 | ||
| 405 | + DataCopy<float, LoadDist::DIST_NORM>(vregInExpSum, inSumUb); // 11 22 ... 32,32 | ||
| 406 | + | ||
| 407 | + | ||
| 408 | + for (uint16_t k = 0; k < (uint16_t)((n + DEQ_BLK - 1) / DEQ_BLK); ++k) { | ||
| 409 | + uint16_t n2 = VF_MIN(n - k * DEQ_BLK, DEQ_BLK); | ||
| 410 | + DataCopy<T, LoadDist::DIST_BRC_B16>(vregScale, scaleUb + k); | ||
| 411 | + | ||
| 412 | + for (uint16_t j = 0; j < (uint16_t)(n2 / R / UNROLL) ; j++) { | ||
| 413 | + uint32_t offset = (k * DEQ_BLK * m) + (j * VL_ELE_B16 * UNROLL); | ||
| 414 | + DataCopy<T, LoadDist::DIST_NORM>(vregSrc0, srcUb + offset + 0); | ||
| 415 | + DataCopy<T, LoadDist::DIST_NORM>(vregSrc1, srcUb + offset + VL_ELE_B16); | ||
| 416 | + DataCopy<T, LoadDist::DIST_NORM>(vregSrc2, srcUb + offset + VL_ELE_B16 *2); | ||
| 417 | + DataCopy<T, LoadDist::DIST_NORM>(vregSrc3, srcUb + offset + VL_ELE_B16 *3); | ||
| 418 | + | ||
| 419 | + Mul(vregSrc0, vregSrc0, vregScale, pregAll); | ||
| 420 | + Mul(vregSrc1, vregSrc1, vregScale, pregAll); | ||
| 421 | + Mul(vregSrc2, vregSrc2, vregScale, pregAll); | ||
| 422 | + Mul(vregSrc3, vregSrc3, vregScale, pregAll); | ||
| 423 | + | ||
| 424 | + Max(vregMax0, vregMax0, vregSrc0, pregAll); | ||
| 425 | + StoreAlign(srcUb + offset + VL_ELE_B16*0 ,vregSrc0, pregAll); | ||
| 426 | + Max(vregMax1, vregMax1, vregSrc1, pregAll); | ||
| 427 | + StoreAlign(srcUb + offset + VL_ELE_B16*1 ,vregSrc1, pregAll); | ||
| 428 | + Max(vregMax2, vregMax2, vregSrc2, pregAll); | ||
| 429 | + StoreAlign(srcUb + offset + VL_ELE_B16*2 ,vregSrc2, pregAll); | ||
| 430 | + Max(vregMax3, vregMax3, vregSrc3, pregAll); | ||
| 431 | + StoreAlign(srcUb + offset + VL_ELE_B16*3 ,vregSrc3, pregAll); | ||
| 432 | + } | ||
| 433 | + } | ||
| 434 | + Max(vregMax0, vregMax0, vregMax1, pregAll); | ||
| 435 | + Max(vregMax2, vregMax2, vregMax3, pregAll); | ||
| 436 | + Max(vregMax0, vregMax0, vregMax2, pregAll); | ||
| 437 | + | ||
| 438 | + Interleave(vregTmp0, vregTmp1, vregMax0, vregMax0); | ||
| 439 | + Max(vregMax1, vregTmp0, vregTmp1, pregAll); // 11 22, ...., 64,64 | ||
| 440 | + Interleave(vregTmp0, vregTmp1, vregMax1, vregMax1); | ||
| 441 | + Max(vregLocalReduce, vregTmp0, vregTmp1, pregAll); // 1111 2222 3333 ... 32,32,32,32 | ||
| 442 | + | ||
| 443 | + // vregLocalReduce is Local max | ||
| 444 | + Max(vregGlobalMax, vregLocalReduce, vregInMax, pregAll); | ||
| 445 | + Sub(vregExpMax16, vregInMax, vregGlobalMax, pregAll); | ||
| 446 | + Exp(vregExpMax16, vregExpMax16, pregAll); | ||
| 447 | + Cast<float, T, castTraitFp32Zero>(vregExpMax32, vregExpMax16, pregAll); // 11 22 33 .... 32,32 | ||
| 448 | + | ||
| 449 | + DeInterleave(vregTmp0, vregTmp1, vregGlobalMax, vregGlobalMax); | ||
| 450 | + DeInterleave(vregInMax, vregTmp1, vregTmp0, vregTmp0); | ||
| 451 | + | ||
| 452 | + LocalMemBar<MemType::VEC_STORE, MemType::VEC_LOAD>(); | ||
| 453 | + Duplicate<T, T>(vregAcc0, (T)0.0f); | ||
| 454 | + Duplicate<T, T>(vregAcc1, (T)0.0f); | ||
| 455 | + Duplicate<T, T>(vregAcc2, (T)0.0f); | ||
| 456 | + Duplicate<T, T>(vregAcc3, (T)0.0f); | ||
| 457 | + | ||
| 458 | + for (uint16_t i = 0; i < (uint16_t)(n >> 4); ++i) { | ||
| 459 | + uint32_t offset = i << 9; // 128 * 4 | ||
| 460 | + DataCopy<T, LoadDist::DIST_NORM>(vregSrc0, srcUb + offset + 0); | ||
| 461 | + DataCopy<T, LoadDist::DIST_NORM>(vregSrc1, srcUb + offset + VL_ELE_B16); | ||
| 462 | + DataCopy<T, LoadDist::DIST_NORM>(vregSrc2, srcUb + offset + VL_ELE_B16 *2); | ||
| 463 | + DataCopy<T, LoadDist::DIST_NORM>(vregSrc3, srcUb + offset + VL_ELE_B16 *3); | ||
| 464 | + | ||
| 465 | + Sub(vregSrc0, vregSrc0, vregInMax, pregAll); | ||
| 466 | + Sub(vregSrc1, vregSrc1, vregInMax, pregAll); | ||
| 467 | + Sub(vregSrc2, vregSrc2, vregInMax, pregAll); | ||
| 468 | + Sub(vregSrc3, vregSrc3, vregInMax, pregAll); | ||
| 469 | + | ||
| 470 | + Exp(vregSrc0, vregSrc0, pregAll); | ||
| 471 | + Exp(vregSrc1, vregSrc1, pregAll); | ||
| 472 | + Exp(vregSrc2, vregSrc2, pregAll); | ||
| 473 | + Exp(vregSrc3, vregSrc3, pregAll); | ||
| 474 | + | ||
| 475 | + Add(vregAcc0, vregAcc0, vregSrc0, pregAll); | ||
| 476 | + Add(vregAcc1, vregAcc1, vregSrc1, pregAll); | ||
| 477 | + Add(vregAcc2, vregAcc2, vregSrc2, pregAll); | ||
| 478 | + Add(vregAcc3, vregAcc3, vregSrc3, pregAll); | ||
| 479 | + | ||
| 480 | + Muls(vregSrc0, vregSrc0, (T)448.0f, pregAll); | ||
| 481 | + Muls(vregSrc1, vregSrc1, (T)448.0f, pregAll); | ||
| 482 | + Muls(vregSrc2, vregSrc2, (T)448.0f, pregAll); | ||
| 483 | + Muls(vregSrc3, vregSrc3, (T)448.0f, pregAll); | ||
| 484 | + | ||
| 485 | + // rna | ||
| 486 | + Maxs((RegTensor<int16_t>&) vregSrc0, (RegTensor<int16_t>&) vregSrc0, (int16_t)(8128+128), pregAll); | ||
| 487 | + Maxs((RegTensor<int16_t>&) vregSrc1, (RegTensor<int16_t>&) vregSrc1, (int16_t)(8128+128), pregAll); | ||
| 488 | + Maxs((RegTensor<int16_t>&) vregSrc2, (RegTensor<int16_t>&) vregSrc2, (int16_t)(8128+128), pregAll); | ||
| 489 | + Maxs((RegTensor<int16_t>&) vregSrc3, (RegTensor<int16_t>&) vregSrc3, (int16_t)(8128+128), pregAll); | ||
| 490 | + | ||
| 491 | + Adds((RegTensor<int16_t>&) vregSrc0, (RegTensor<int16_t>&) vregSrc0, (int16_t)(-8128), pregAll); | ||
| 492 | + Adds((RegTensor<int16_t>&) vregSrc1, (RegTensor<int16_t>&) vregSrc1, (int16_t)(-8128), pregAll); | ||
| 493 | + Adds((RegTensor<int16_t>&) vregSrc2, (RegTensor<int16_t>&) vregSrc2, (int16_t)(-8128), pregAll); | ||
| 494 | + Adds((RegTensor<int16_t>&) vregSrc3, (RegTensor<int16_t>&) vregSrc3, (int16_t)(-8128), pregAll); | ||
| 495 | + | ||
| 496 | + ShiftRights((RegTensor<int16_t>&) vregSrc0, (RegTensor<int16_t>&) vregSrc0, (int16_t)7, pregAll); | ||
| 497 | + ShiftRights((RegTensor<int16_t>&) vregSrc1, (RegTensor<int16_t>&) vregSrc1, (int16_t)7, pregAll); | ||
| 498 | + ShiftRights((RegTensor<int16_t>&) vregSrc2, (RegTensor<int16_t>&) vregSrc2, (int16_t)7, pregAll); | ||
| 499 | + ShiftRights((RegTensor<int16_t>&) vregSrc3, (RegTensor<int16_t>&) vregSrc3, (int16_t)7, pregAll); | ||
| 500 | + | ||
| 501 | + StoreAlign<T2, StoreDist::DIST_PACK_B16>(dstUb + offset + VL_ELE_B16 * 0, (RegTensor<T2>&) vregSrc0, pregAll); | ||
| 502 | + StoreAlign<T2, StoreDist::DIST_PACK_B16>(dstUb + offset + VL_ELE_B16 * 1, (RegTensor<T2>&) vregSrc1, pregAll); | ||
| 503 | + StoreAlign<T2, StoreDist::DIST_PACK_B16>(dstUb + offset + VL_ELE_B16 * 2, (RegTensor<T2>&) vregSrc2, pregAll); | ||
| 504 | + StoreAlign<T2, StoreDist::DIST_PACK_B16>(dstUb + offset + VL_ELE_B16 * 3, (RegTensor<T2>&) vregSrc3, pregAll); // B16 mask reg need | ||
| 505 | + } | ||
| 506 | + Add(vregAcc0, vregAcc0, vregAcc1, pregAll); | ||
| 507 | + Add(vregAcc2, vregAcc2, vregAcc3, pregAll); | ||
| 508 | + Add(vregAcc0, vregAcc0, vregAcc2, pregAll); | ||
| 509 | + | ||
| 510 | + Interleave(vregTmp0, vregTmp1, vregAcc0, vregAcc0); | ||
| 511 | + Add(vregAcc1, vregTmp0, vregTmp1, pregAll); | ||
| 512 | + Interleave(vregTmp0, vregTmp1, vregAcc1, vregAcc1); | ||
| 513 | + Add(vregLocalReduce, vregTmp0, vregTmp1, pregAll); // 1111 2222 .... 32,32,32,32 | ||
| 514 | + Cast<float, T, castTraitFp32Zero>(vregExpSum32, vregLocalReduce, pregAll); // 11 22 ... 32,32 | ||
| 515 | + | ||
| 516 | + // x_sum = sum(exp_max * in_sum + x_sum) | ||
| 517 | + Mul<float, MaskMergeMode::ZEROING>(vregInExpSum, vregExpMax32, vregInExpSum, pregAll32); | ||
| 518 | + Add<float, MaskMergeMode::ZEROING>(vregInExpSum, vregInExpSum, vregExpSum32, pregAll32); | ||
| 519 | + | ||
| 520 | + DataCopy<float, StoreDist::DIST_NORM>(expSumUb, vregInExpSum, pregAll32); | ||
| 521 | + DataCopy<float, StoreDist::DIST_NORM>(expMaxUb, vregExpMax32, pregAll32); | ||
| 522 | + DataCopy<T, StoreDist::DIST_NORM>(maxUb, vregGlobalMax, pregAll); | ||
| 523 | + } | ||
| 524 | + } | ||
| 525 | +}; | ||
| 526 | +} | ||
| 527 | + | ||
| 528 | + | ||
| @@ -0,0 +1,684 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +namespace NpuArch::Epilogue::Block { | ||
| 24 | + | ||
| 25 | +enum class KvBaseTileRegSplitStagesBf16 { | ||
| 26 | + ONE, | ||
| 27 | + TWO | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | +template < | ||
| 31 | + class OutputType_, | ||
| 32 | + class LayoutS_> | ||
| 33 | +class BlockEpilogue< | ||
| 34 | + EpilogueOnlineSoftmaxBsa, | ||
| 35 | + OutputType_, | ||
| 36 | + Gemm::GemmType<bfloat16_t, LayoutS_>> | ||
| 37 | +{ | ||
| 38 | +public: | ||
| 39 | + using DispatchPolicy = EpilogueOnlineSoftmaxBsa; | ||
| 40 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 41 | + using ElementOutput = typename OutputType_::Element; | ||
| 42 | + using ElementInput = bfloat16_t; | ||
| 43 | + | ||
| 44 | + using LayoutOutput = typename OutputType_::Layout; | ||
| 45 | + using LayoutInput = LayoutS_; | ||
| 46 | + | ||
| 47 | + static constexpr uint32_t BLOCK_SIZE_IN_BYTE = 32; | ||
| 48 | + static constexpr uint32_t REPEAT_SIZE_IN_BYTE = 256; | ||
| 49 | + static constexpr uint32_t FLOAT_BLOCK_SIZE = 8; | ||
| 50 | + static constexpr uint32_t FLOAT_VECTOR_SIZE = 64; | ||
| 51 | + static constexpr uint32_t HALF_VECTOR_SIZE = 128; | ||
| 52 | + static constexpr uint32_t BLOCK_SIZE = 16; | ||
| 53 | + static constexpr uint32_t UB_UINT8_VECTOR_SIZE = 1024; | ||
| 54 | + static constexpr uint32_t UB_UINT8_BLOCK_SIZE = 32768; | ||
| 55 | + static constexpr uint32_t VECTOR_SIZE = 128; | ||
| 56 | + static constexpr uint32_t MAX_UB_S_ELEM_NUM = 16384; | ||
| 57 | + static constexpr uint32_t DM_UB_GLOBAL_ELEM_NUM = 64; | ||
| 58 | + static constexpr uint32_t ELE_NUM_PER_C0 = 16; | ||
| 59 | + static constexpr uint32_t C0_NUM_PER_FRACTAL = 16; | ||
| 60 | + | ||
| 61 | + static constexpr uint32_t REDUCE_UB_SIZE = 1024; | ||
| 62 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_32 = 32; | ||
| 63 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_8 = 8; | ||
| 64 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_4 = 4; | ||
| 65 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_2 = 2; | ||
| 66 | + static constexpr uint32_t MAX_ROW_NUM_SUB_CORE = 256; | ||
| 67 | + static constexpr int64_t UB_FLOAT_LINE_SIZE = 64; | ||
| 68 | + | ||
| 69 | + static constexpr uint32_t SPLIT_COL_IDX_2 = 2; | ||
| 70 | + static constexpr uint32_t SPLIT_COL_IDX_3 = 3; | ||
| 71 | + static constexpr uint32_t HALF_REP_SIZE = 128; | ||
| 72 | + static constexpr uint32_t FLOAT_REP_SIZE = 64; | ||
| 73 | + static constexpr uint32_t BLOCK_REP_SIZE = 8; | ||
| 74 | + static constexpr uint32_t REPEAT_STRIDE = 1; | ||
| 75 | + static constexpr uint32_t SM_ROW_MAX_ELEM_NUM = 64; | ||
| 76 | + static constexpr uint32_t SM_COL_MAX_ELEM_NUM = 256; | ||
| 77 | + static constexpr uint32_t SM_VREG_SIZE = 256 / sizeof(ElementInput); | ||
| 78 | + | ||
| 79 | + __aicore__ inline | ||
| 80 | + BlockEpilogue(Arch::Resource<ArchTag> &resource, float scaleValue_) | ||
| 81 | + { | ||
| 82 | + // Allocate UB space | ||
| 83 | + constexpr uint32_t LS_UB_TENSOR_OFFSET = 0; | ||
| 84 | + constexpr uint32_t LP_UB_TENSOR_OFFSET = 2 * UB_UINT8_BLOCK_SIZE; | ||
| 85 | + | ||
| 86 | + constexpr uint32_t LM_UB_TENSOR_OFFSET = 7 * UB_UINT8_BLOCK_SIZE; | ||
| 87 | + constexpr uint32_t GM_UB_TENSOR_OFFSET = LM_UB_TENSOR_OFFSET + 64 * sizeof(float); | ||
| 88 | + constexpr uint32_t DM_UB_TENSOR_OFFSET = GM_UB_TENSOR_OFFSET + 64 * sizeof(float); | ||
| 89 | + constexpr uint32_t LL_UB_TENSOR_OFFSET = DM_UB_TENSOR_OFFSET + 3 * 64 * sizeof(float); | ||
| 90 | + constexpr uint32_t GL_UB_TENSOR_OFFSET = LL_UB_TENSOR_OFFSET + 64 * sizeof(float); | ||
| 91 | + | ||
| 92 | + subBlockIdx_ = AscendC::GetSubBlockIdx(); | ||
| 93 | + scaleValue = AscendC::ToBfloat16(scaleValue_); | ||
| 94 | + MIN_VALUE = AscendC::ToBfloat16(-3.389531390315715675e+38); | ||
| 95 | + | ||
| 96 | + lsUbTensor = resource.ubBuf.template GetBufferByByte<ElementInput>(LS_UB_TENSOR_OFFSET); | ||
| 97 | + lpUbTensor = resource.ubBuf.template GetBufferByByte<ElementOutput>(LP_UB_TENSOR_OFFSET); | ||
| 98 | + gmUbTensor = resource.ubBuf.template GetBufferByByte<float>(GM_UB_TENSOR_OFFSET); | ||
| 99 | + glUbTensor = resource.ubBuf.template GetBufferByByte<float>(GL_UB_TENSOR_OFFSET); | ||
| 100 | + dmUbTensor = resource.ubBuf.template GetBufferByByte<float>(DM_UB_TENSOR_OFFSET); | ||
| 101 | + lmUbTensor = resource.ubBuf.template GetBufferByByte<ElementInput>(LM_UB_TENSOR_OFFSET); | ||
| 102 | + llUbTensor = resource.ubBuf.template GetBufferByByte<ElementInput>(LL_UB_TENSOR_OFFSET); | ||
| 103 | + lmUbFloatTensor = resource.ubBuf.template GetBufferByByte<float>(LM_UB_TENSOR_OFFSET); | ||
| 104 | + llUbFloatTensor = resource.ubBuf.template GetBufferByByte<float>(LL_UB_TENSOR_OFFSET); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + __aicore__ inline | ||
| 108 | + ~BlockEpilogue() | ||
| 109 | + { | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + template <class TensorDst, class TensorSrc> | ||
| 113 | + __aicore__ inline | ||
| 114 | + void CopyPUbToPL1(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint32_t m) | ||
| 115 | + { | ||
| 116 | + const uint32_t blockCount = tla::get<1, 1>(srcTensor.shape()); | ||
| 117 | + const uint32_t blockLen = tla::get<0, 0>(srcTensor.shape()) * tla::get<0, 1>(srcTensor.shape()); | ||
| 118 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 119 | + | ||
| 120 | + AscendC::DataCopyParams repeatParams; | ||
| 121 | + | ||
| 122 | + repeatParams.blockCount = blockCount; | ||
| 123 | + repeatParams.blockLen = m; | ||
| 124 | + repeatParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / ELE_NUM_PER_C0 - m; | ||
| 125 | + repeatParams.dstStride = tla::get<1, 1>(dstTensor.stride()) / ELE_NUM_PER_C0 - m; | ||
| 126 | + | ||
| 127 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 128 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 129 | + | ||
| 130 | + AscendC::DataCopy(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], repeatParams); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 134 | + __aicore__ inline | ||
| 135 | + void SetCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 136 | + { | ||
| 137 | + // in mode 4, AIC set for 2 AIVs seperately | ||
| 138 | + if constexpr (MODE == 4U) { | ||
| 139 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlag); | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 144 | + __aicore__ inline | ||
| 145 | + void WaitCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 146 | + { | ||
| 147 | + // in mode 4, AIC wait for 2 AIVs seperately | ||
| 148 | + if constexpr (MODE == 4U) { | ||
| 149 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlag); | ||
| 150 | + } | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + template <class TensorP> | ||
| 154 | + __aicore__ inline | ||
| 155 | + void operator()(TensorP &l1PTensorTla, GemmCoord actualBlockShape, | ||
| 156 | + uint32_t isFirstKvSTile, uint32_t ubSBufId, uint32_t l1PBufId, | ||
| 157 | + Arch::CrossCoreFlag mm1ToSmFlag, Arch::CrossCoreFlag smToMm2Flag, | ||
| 158 | + int actualRownum=0){ | ||
| 159 | + | ||
| 160 | + struct EmptyTensor {}; | ||
| 161 | + EmptyTensor dummyQS; | ||
| 162 | + EmptyTensor dummyKS; | ||
| 163 | + operator()<0>(l1PTensorTla, dummyQS, dummyKS, | ||
| 164 | + actualBlockShape, | ||
| 165 | + isFirstKvSTile, ubSBufId, l1PBufId, | ||
| 166 | + mm1ToSmFlag, smToMm2Flag, AscendC::GlobalTensor<int32_t>(), | ||
| 167 | + 0, actualRownum); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + template <int quant_mode, class TensorP, class TensorQS, class TensorKS, typename ElementIndex> | ||
| 171 | + __aicore__ inline | ||
| 172 | + void operator()(TensorP &l1PTensorTla, TensorQS &gmQSTensorTla, TensorKS &gmKSTensorTla, | ||
| 173 | + GemmCoord actualBlockShape, | ||
| 174 | + uint32_t isFirstKvSTile, uint32_t ubSBufId, uint32_t l1PBufId, | ||
| 175 | + Arch::CrossCoreFlag mm1ToSmFlag, Arch::CrossCoreFlag smToMm2Flag, | ||
| 176 | + AscendC::GlobalTensor<ElementIndex> sparseIndex, int blockNum=0, int actualRownum=0) | ||
| 177 | + { | ||
| 178 | + uint32_t mCopyOffset = (actualRownum > 0) ? | ||
| 179 | + static_cast<uint32_t>(actualRownum) / 2 : RoundUp(actualBlockShape.m(), 8) / 2; | ||
| 180 | + uint32_t m = actualBlockShape.m() < mCopyOffset ? actualBlockShape.m() : mCopyOffset; | ||
| 181 | + m = subBlockIdx_ == 0 ? m : actualBlockShape.m() - m; | ||
| 182 | + if (m == 0) { | ||
| 183 | + WaitCrossCoreSync<4, PIPE_V>(mm1ToSmFlag); | ||
| 184 | + SetCrossCoreSync<4, PIPE_V>(mm1ToSmFlag); | ||
| 185 | + WaitCrossCoreSync<4, PIPE_MTE3>(smToMm2Flag); | ||
| 186 | + SetCrossCoreSync<4, PIPE_MTE3>(smToMm2Flag); | ||
| 187 | + return; | ||
| 188 | + } | ||
| 189 | + uint32_t n = actualBlockShape.n(); | ||
| 190 | + uint16_t mRound = RoundUp(m, C0_NUM_PER_FRACTAL); | ||
| 191 | + uint16_t nRound = RoundUp(n, ELE_NUM_PER_C0); | ||
| 192 | + uint32_t blockStride = mRound; | ||
| 193 | + constexpr int16_t vlSize = static_cast<int16_t>(AscendC::GetVecLen() / sizeof(ElementInput)); | ||
| 194 | + constexpr int16_t vlFloatSize = static_cast<int16_t>(AscendC::GetVecLen() / sizeof(float)); | ||
| 195 | + int16_t nLoops = AscendC::CeilDivision(n, vlSize) - 1; | ||
| 196 | + uint32_t tailN = (n - 1) % vlSize + 1; | ||
| 197 | + int16_t mLoops = AscendC::CeilDivision(m, vlFloatSize) - 1; | ||
| 198 | + uint32_t tailM = (m - 1) % vlFloatSize + 1; | ||
| 199 | + uint32_t nPadding = (tailN + BLOCK_SIZE_IN_BYTE - 1) / BLOCK_SIZE_IN_BYTE * BLOCK_SIZE_IN_BYTE; | ||
| 200 | + __ubuf__ ElementOutput *pAddr = (__ubuf__ ElementOutput*) lpUbTensor[ubSBufId * MAX_UB_S_ELEM_NUM].GetPhyAddr(); | ||
| 201 | + __ubuf__ ElementInput *sAddr = (__ubuf__ ElementInput*) lsUbTensor[ubSBufId * MAX_UB_S_ELEM_NUM].GetPhyAddr(); | ||
| 202 | + __ubuf__ float *lastMaxAddr = (__ubuf__ float *)gmUbTensor.GetPhyAddr(); | ||
| 203 | + __ubuf__ float *lastSumAddr = (__ubuf__ float*) glUbTensor.GetPhyAddr(); | ||
| 204 | + __ubuf__ ElementInput *nowMaxAddr = (__ubuf__ ElementInput*) lmUbTensor.GetPhyAddr(); | ||
| 205 | + __ubuf__ float *nowMaxFloatAddr = (__ubuf__ float*) lmUbFloatTensor.GetPhyAddr(); | ||
| 206 | + __ubuf__ float *nowSumAddr = (__ubuf__ float*) llUbFloatTensor.GetPhyAddr(); | ||
| 207 | + __ubuf__ float *expMaxUbAddr = (__ubuf__ float *)dmUbTensor[l1PBufId * DM_UB_GLOBAL_ELEM_NUM].GetPhyAddr(); | ||
| 208 | + | ||
| 209 | + // wait QK Fixpipe finsh | ||
| 210 | + WaitCrossCoreSync<4, PIPE_V>(mm1ToSmFlag); | ||
| 211 | + if (isFirstKvSTile) { | ||
| 212 | + nowMaxFloatAddr = lastMaxAddr; | ||
| 213 | + nowSumAddr = lastSumAddr; | ||
| 214 | + } | ||
| 215 | + uint32_t kvBaseTileRegStages = CeilDiv(n, SM_VREG_SIZE); | ||
| 216 | + if (kvBaseTileRegStages == 1) { | ||
| 217 | + ComputeScaleAndMax<KvBaseTileRegSplitStagesBf16::ONE>( | ||
| 218 | + sAddr, nowMaxFloatAddr, m, tailN, nPadding, scaleValue, nRound); | ||
| 219 | + } else if (kvBaseTileRegStages == 2) { | ||
| 220 | + ComputeScaleAndMax<KvBaseTileRegSplitStagesBf16::TWO>( | ||
| 221 | + sAddr, nowMaxFloatAddr, m, tailN, nPadding, scaleValue, nRound); | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + if (!isFirstKvSTile) { | ||
| 225 | + UpdateMax(nowMaxFloatAddr, lastMaxAddr, mLoops, tailM); | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(ubSBufId + 2); | ||
| 229 | + uint32_t tailNOdd = tailN / 2 ; | ||
| 230 | + uint32_t tailNEven = tailNOdd + tailN % 2; | ||
| 231 | + if (kvBaseTileRegStages == 1) { | ||
| 232 | + ComputeExpSubSum16<KvBaseTileRegSplitStagesBf16::ONE>( | ||
| 233 | + pAddr, sAddr, nowMaxFloatAddr, nowSumAddr, m, tailN, blockStride, nRound, tailNOdd, tailNEven); | ||
| 234 | + } else if (kvBaseTileRegStages == 2) { | ||
| 235 | + ComputeExpSubSum16<KvBaseTileRegSplitStagesBf16::TWO>( | ||
| 236 | + pAddr, sAddr, nowMaxFloatAddr, nowSumAddr, m, tailN, blockStride, nRound, tailNOdd, tailNEven); | ||
| 237 | + } | ||
| 238 | + | ||
| 239 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(ubSBufId); | ||
| 240 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(ubSBufId); | ||
| 241 | + SetCrossCoreSync<4, PIPE_V>(mm1ToSmFlag); | ||
| 242 | + | ||
| 243 | + auto ubPLayoutTla = tla::MakeLayout<ElementOutput, LayoutOutput>(mRound, nRound); | ||
| 244 | + auto ubPTensorTla = tla::MakeTensor(lpUbTensor[ubSBufId * MAX_UB_S_ELEM_NUM], | ||
| 245 | + ubPLayoutTla, Arch::PositionUB{}); | ||
| 246 | + auto ubPTensorTlaTile = GetTile(ubPTensorTla, | ||
| 247 | + tla::MakeCoord(0, 0), tla::MakeShape(m, n)); | ||
| 248 | + auto l1PTensorTlaTile = GetTile(l1PTensorTla, | ||
| 249 | + tla::MakeCoord(subBlockIdx_ * mCopyOffset, 0), tla::MakeShape(m, n)); | ||
| 250 | + WaitCrossCoreSync<4, PIPE_MTE3>(smToMm2Flag); | ||
| 251 | + CopyPUbToPL1(l1PTensorTlaTile, ubPTensorTlaTile, m); | ||
| 252 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(ubSBufId + 2); | ||
| 253 | + // crossCoreSync after PIPE_MTE1 move | ||
| 254 | + SetCrossCoreSync<4, PIPE_MTE3>(smToMm2Flag); | ||
| 255 | + if (!isFirstKvSTile) { | ||
| 256 | + UpdateExpSumAndExpMax( | ||
| 257 | + lastSumAddr, expMaxUbAddr, lastMaxAddr, nowSumAddr, nowMaxFloatAddr, mLoops, tailM); | ||
| 258 | + } | ||
| 259 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | +private: | ||
| 263 | + ElementInput scaleValue; | ||
| 264 | + AscendC::LocalTensor<ElementInput> lsUbTensor; | ||
| 265 | + AscendC::LocalTensor<ElementOutput> lpUbTensor; | ||
| 266 | + AscendC::LocalTensor<float> gmUbTensor; | ||
| 267 | + AscendC::LocalTensor<float> glUbTensor; | ||
| 268 | + AscendC::LocalTensor<float> dmUbTensor; | ||
| 269 | + AscendC::LocalTensor<ElementInput> lmUbTensor; | ||
| 270 | + AscendC::LocalTensor<ElementInput> llUbTensor; | ||
| 271 | + AscendC::LocalTensor<float> lmUbFloatTensor; | ||
| 272 | + AscendC::LocalTensor<float> llUbFloatTensor; | ||
| 273 | + uint32_t subBlockIdx_; | ||
| 274 | + ElementInput MIN_VALUE; | ||
| 275 | + | ||
| 276 | + template <KvBaseTileRegSplitStagesBf16 kvBaseTileRegSplitStages> | ||
| 277 | + __simd_vf__ inline void ComputeScaleAndMax( | ||
| 278 | + __ubuf__ ElementInput *srcUb, __ubuf__ float *newMaxUb, | ||
| 279 | + uint16_t m, uint32_t tailN, uint32_t nPadding, ElementInput dScale, uint16_t S2BaseSize) | ||
| 280 | + { | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + template <> | ||
| 284 | + __simd_vf__ inline void ComputeScaleAndMax<KvBaseTileRegSplitStagesBf16::ONE>( | ||
| 285 | + __ubuf__ ElementInput *srcUb, __ubuf__ float *newMaxUb, | ||
| 286 | + uint16_t m, uint32_t tailN, uint32_t nPadding, ElementInput dScale, uint16_t S2BaseSize) | ||
| 287 | + { | ||
| 288 | + using namespace AscendC::MicroAPI; | ||
| 289 | + | ||
| 290 | + constexpr static CastTrait castTraitZero = { | ||
| 291 | + RegLayout::ZERO, | ||
| 292 | + SatMode::UNKNOWN, | ||
| 293 | + MaskMergeMode::ZEROING, | ||
| 294 | + AscendC::RoundMode::UNKNOWN, | ||
| 295 | + }; | ||
| 296 | + constexpr static CastTrait castTraitOne = { | ||
| 297 | + RegLayout::ONE, | ||
| 298 | + SatMode::UNKNOWN, | ||
| 299 | + MaskMergeMode::ZEROING, | ||
| 300 | + AscendC::RoundMode::UNKNOWN, | ||
| 301 | + }; | ||
| 302 | + | ||
| 303 | + RegTensor<ElementInput> minVreg; | ||
| 304 | + RegTensor<ElementInput> srcVreg; | ||
| 305 | + // RegTensor<ElementInput> maxSrcVreg; | ||
| 306 | + RegTensor<ElementInput> maxTmpVreg; | ||
| 307 | + RegTensor<ElementInput> scaleVreg; | ||
| 308 | + RegTensor<float> maxFloatVreg0; | ||
| 309 | + RegTensor<float> maxFloatVreg1; | ||
| 310 | + RegTensor<float> maxTmpFloatVreg; | ||
| 311 | + RegTensor<float> maxTmpFloatVreg0; | ||
| 312 | + RegTensor<float> maxTmpFloatVreg1; | ||
| 313 | + UnalignReg maxUreg; | ||
| 314 | + MaskReg pregCompare; | ||
| 315 | + MaskReg pregFull = CreateMask<ElementInput, MaskPattern::ALL>(); | ||
| 316 | + MaskReg pregFloatFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 317 | + MaskReg pregTailN = UpdateMask<ElementInput>(tailN); | ||
| 318 | + MaskReg pregFloatTailN = UpdateMask<float>(tailN); | ||
| 319 | + | ||
| 320 | + Duplicate(minVreg, MIN_VALUE); | ||
| 321 | + Duplicate(scaleVreg, dScale); | ||
| 322 | + for (uint16_t i = 0; i < m; ++i) { | ||
| 323 | + LoadAlign(srcVreg, srcUb + i * S2BaseSize); | ||
| 324 | + Mul(srcVreg, srcVreg, scaleVreg, pregFull); | ||
| 325 | + Select(srcVreg, srcVreg, minVreg, pregTailN); | ||
| 326 | + StoreAlign<ElementInput, StoreDist::DIST_NORM_B16>( | ||
| 327 | + srcUb + i * S2BaseSize, srcVreg, pregTailN); | ||
| 328 | + Cast<float, ElementInput, castTraitZero>(maxFloatVreg0, srcVreg, pregFull); | ||
| 329 | + Cast<float, ElementInput, castTraitOne>(maxFloatVreg1, srcVreg, pregFull); | ||
| 330 | + ReduceMax(maxTmpFloatVreg0, maxFloatVreg0, pregFull); | ||
| 331 | + ReduceMax(maxTmpFloatVreg1, maxFloatVreg1, pregFull); | ||
| 332 | + Max(maxTmpFloatVreg, maxTmpFloatVreg0, maxTmpFloatVreg1, pregFull); | ||
| 333 | + StoreUnAlign<float, PostLiteral::POST_MODE_UPDATE>(newMaxUb, maxTmpFloatVreg, maxUreg, 1); | ||
| 334 | + } | ||
| 335 | + vstas(maxUreg, newMaxUb, 0, POST_UPDATE); | ||
| 336 | + } | ||
| 337 | + | ||
| 338 | + template <> | ||
| 339 | + __simd_vf__ inline void ComputeScaleAndMax<KvBaseTileRegSplitStagesBf16::TWO>( | ||
| 340 | + __ubuf__ ElementInput *srcUb, __ubuf__ float *newMaxUb, | ||
| 341 | + uint16_t m, uint32_t tailN, uint32_t nPadding, ElementInput dScale, uint16_t S2BaseSize) | ||
| 342 | + { | ||
| 343 | + using namespace AscendC::MicroAPI; | ||
| 344 | + constexpr static CastTrait castTraitZero = { | ||
| 345 | + RegLayout::ZERO, | ||
| 346 | + SatMode::UNKNOWN, | ||
| 347 | + MaskMergeMode::ZEROING, | ||
| 348 | + AscendC::RoundMode::UNKNOWN, | ||
| 349 | + }; | ||
| 350 | + constexpr static CastTrait castTraitOne = { | ||
| 351 | + RegLayout::ONE, | ||
| 352 | + SatMode::UNKNOWN, | ||
| 353 | + MaskMergeMode::ZEROING, | ||
| 354 | + AscendC::RoundMode::UNKNOWN, | ||
| 355 | + }; | ||
| 356 | + | ||
| 357 | + RegTensor<ElementInput> minVreg; | ||
| 358 | + RegTensor<ElementInput> srcVreg0; | ||
| 359 | + RegTensor<ElementInput> srcVreg1; | ||
| 360 | + // RegTensor<ElementInput> maxSrcVreg; | ||
| 361 | + RegTensor<ElementInput> maxTmpVreg; | ||
| 362 | + RegTensor<ElementInput> scaleVreg; | ||
| 363 | + RegTensor<float> maxFloatVreg0; | ||
| 364 | + RegTensor<float> maxFloatVreg1; | ||
| 365 | + RegTensor<float> maxTmpFloatVreg; | ||
| 366 | + RegTensor<float> maxTmpFloatVreg0; | ||
| 367 | + RegTensor<float> maxTmpFloatVreg1; | ||
| 368 | + UnalignReg maxUreg; | ||
| 369 | + MaskReg pregCompare; | ||
| 370 | + MaskReg pregFull = CreateMask<ElementInput, MaskPattern::ALL>(); | ||
| 371 | + MaskReg pregFloatFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 372 | + MaskReg pregTailN = UpdateMask<ElementInput>(tailN); | ||
| 373 | + MaskReg pregFloatTailN = UpdateMask<float>(tailN); | ||
| 374 | + | ||
| 375 | + Duplicate(minVreg, MIN_VALUE); | ||
| 376 | + Duplicate(scaleVreg, dScale); | ||
| 377 | + for (uint16_t i = 0; i < m; ++i) { | ||
| 378 | + LoadAlign(srcVreg0, srcUb + i * S2BaseSize); | ||
| 379 | + LoadAlign(srcVreg1, srcUb + i * S2BaseSize + HALF_REP_SIZE); | ||
| 380 | + Mul(srcVreg0, srcVreg0, scaleVreg, pregFull); | ||
| 381 | + Mul(srcVreg1, srcVreg1, scaleVreg, pregFull); | ||
| 382 | + StoreAlign<ElementInput, StoreDist::DIST_NORM_B16>( | ||
| 383 | + srcUb + i * S2BaseSize, srcVreg0, pregFull); | ||
| 384 | + StoreAlign<ElementInput, StoreDist::DIST_NORM_B16>( | ||
| 385 | + srcUb + i * S2BaseSize + HALF_REP_SIZE, srcVreg1, pregTailN); | ||
| 386 | + Max<ElementInput, MaskMergeMode::MERGING>(srcVreg0, srcVreg0, srcVreg1, pregTailN); | ||
| 387 | + | ||
| 388 | + Cast<float, ElementInput, castTraitZero>(maxFloatVreg0, srcVreg0, pregFull); | ||
| 389 | + Cast<float, ElementInput, castTraitOne>(maxFloatVreg1, srcVreg0, pregFull); | ||
| 390 | + ReduceMax(maxTmpFloatVreg0, maxFloatVreg0, pregFull); | ||
| 391 | + ReduceMax(maxTmpFloatVreg1, maxFloatVreg1, pregFull); | ||
| 392 | + Max(maxTmpFloatVreg, maxTmpFloatVreg0, maxTmpFloatVreg1, pregFull); | ||
| 393 | + StoreUnAlign<float, PostLiteral::POST_MODE_UPDATE>(newMaxUb, maxTmpFloatVreg, maxUreg, 1); | ||
| 394 | + } | ||
| 395 | + vstas(maxUreg, newMaxUb, 0, POST_UPDATE); | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + template <typename ElementS> | ||
| 399 | + __simd_vf__ inline void CastMax( | ||
| 400 | + __ubuf__ ElementS *nowMaxUb, __ubuf__ float *nowMaxFloatUb, uint16_t mLoops, uint32_t tailM) | ||
| 401 | + { | ||
| 402 | + using namespace AscendC::MicroAPI; | ||
| 403 | + constexpr static CastTrait castTraitZero = { | ||
| 404 | + RegLayout::ZERO, | ||
| 405 | + SatMode::UNKNOWN, | ||
| 406 | + MaskMergeMode::ZEROING, | ||
| 407 | + AscendC::RoundMode::UNKNOWN, | ||
| 408 | + }; | ||
| 409 | + | ||
| 410 | + RegTensor<ElementS> nowMaxVreg; | ||
| 411 | + RegTensor<float> nowMaxFloatVreg; | ||
| 412 | + RegTensor<ElementS> maxVreg; | ||
| 413 | + | ||
| 414 | + MaskReg pregFull = CreateMask<ElementS, MaskPattern::ALL>(); | ||
| 415 | + MaskReg pregFloatFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 416 | + MaskReg pregTailM = UpdateMask<ElementS>(tailM); | ||
| 417 | + MaskReg pregFloatTailM = UpdateMask<float>(tailM); | ||
| 418 | + for (uint16_t i = 0; i < mLoops; ++i) { | ||
| 419 | + LoadAlign(nowMaxVreg, nowMaxUb + i * HALF_REP_SIZE); | ||
| 420 | + Cast<float, ElementS, castTraitZero>(nowMaxFloatVreg, nowMaxVreg, pregFull); | ||
| 421 | + StoreAlign<float, StoreDist::DIST_NORM_B32>( | ||
| 422 | + nowMaxFloatUb + i * FLOAT_REP_SIZE, nowMaxFloatVreg, pregFloatFull); | ||
| 423 | + } | ||
| 424 | + LoadAlign(nowMaxVreg, nowMaxUb + mLoops * HALF_REP_SIZE); | ||
| 425 | + Cast<float, ElementS, castTraitZero>(nowMaxFloatVreg, nowMaxVreg, pregFull); | ||
| 426 | + StoreAlign<float, StoreDist::DIST_NORM_B32>( | ||
| 427 | + nowMaxFloatUb + mLoops * FLOAT_REP_SIZE, nowMaxFloatVreg, pregFloatTailM); | ||
| 428 | + } | ||
| 429 | + | ||
| 430 | + __simd_vf__ inline void UpdateMax( | ||
| 431 | + __ubuf__ float *nowMaxUb, __ubuf__ float *lastMaxUb, uint16_t mLoops, uint32_t tailM) | ||
| 432 | + { | ||
| 433 | + using namespace AscendC::MicroAPI; | ||
| 434 | + | ||
| 435 | + RegTensor<float> nowMaxVreg; | ||
| 436 | + RegTensor<float> lastMaxFloatVreg; | ||
| 437 | + RegTensor<float> maxVreg; | ||
| 438 | + | ||
| 439 | + MaskReg pregFloatFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 440 | + MaskReg pregFloatTailM = UpdateMask<float>(tailM); | ||
| 441 | + for (uint16_t i = 0; i < mLoops; ++i) { | ||
| 442 | + LoadAlign(lastMaxFloatVreg, lastMaxUb + i * FLOAT_REP_SIZE); | ||
| 443 | + LoadAlign(nowMaxVreg, nowMaxUb + i * FLOAT_REP_SIZE); | ||
| 444 | + Max(maxVreg, nowMaxVreg, lastMaxFloatVreg, pregFloatFull); | ||
| 445 | + StoreAlign<float, StoreDist::DIST_NORM_B32>(nowMaxUb + i * FLOAT_REP_SIZE, maxVreg, pregFloatFull); | ||
| 446 | + } | ||
| 447 | + LoadAlign(lastMaxFloatVreg, lastMaxUb + mLoops * FLOAT_REP_SIZE); | ||
| 448 | + LoadAlign(nowMaxVreg, nowMaxUb + mLoops * FLOAT_REP_SIZE); | ||
| 449 | + Max(maxVreg, nowMaxVreg, lastMaxFloatVreg, pregFloatFull); | ||
| 450 | + StoreAlign<float, StoreDist::DIST_NORM_B32>(nowMaxUb + mLoops * FLOAT_REP_SIZE, maxVreg, pregFloatTailM); | ||
| 451 | + } | ||
| 452 | + | ||
| 453 | + template <KvBaseTileRegSplitStagesBf16 kvBaseTileRegSplitStages> | ||
| 454 | + __simd_vf__ inline void ComputeExpSubSum16( | ||
| 455 | + __ubuf__ ElementOutput *expUb, __ubuf__ ElementInput *srcUb, | ||
| 456 | + __ubuf__ float *nowMaxUb, __ubuf__ float *expSumUb, | ||
| 457 | + uint16_t m, uint32_t tailN, uint32_t blockStride, | ||
| 458 | + uint16_t S2BaseSize, uint32_t tailNOdd, uint32_t tailNEven) | ||
| 459 | + { | ||
| 460 | + } | ||
| 461 | + | ||
| 462 | + template <> | ||
| 463 | + __simd_vf__ inline void ComputeExpSubSum16<KvBaseTileRegSplitStagesBf16::ONE>( | ||
| 464 | + __ubuf__ ElementOutput *expUb, __ubuf__ ElementInput *srcUb, | ||
| 465 | + __ubuf__ float *nowMaxUb, __ubuf__ float *expSumUb, | ||
| 466 | + uint16_t m, uint32_t tailN, uint32_t blockStride, | ||
| 467 | + uint16_t S2BaseSize, uint32_t tailNOdd, uint32_t tailNEven) | ||
| 468 | + { | ||
| 469 | + using namespace AscendC::MicroAPI; | ||
| 470 | + constexpr static CastTrait castTraitZero = { | ||
| 471 | + RegLayout::ZERO, | ||
| 472 | + SatMode::UNKNOWN, | ||
| 473 | + MaskMergeMode::ZEROING, | ||
| 474 | + AscendC::RoundMode::UNKNOWN, | ||
| 475 | + }; | ||
| 476 | + constexpr static CastTrait castTraitOne = { | ||
| 477 | + RegLayout::ONE, | ||
| 478 | + SatMode::UNKNOWN, | ||
| 479 | + MaskMergeMode::ZEROING, | ||
| 480 | + AscendC::RoundMode::UNKNOWN, | ||
| 481 | + }; | ||
| 482 | + | ||
| 483 | + constexpr static CastTrait castTraitZeroDown = { | ||
| 484 | + RegLayout::ZERO, | ||
| 485 | + SatMode::SAT, | ||
| 486 | + MaskMergeMode::ZEROING, | ||
| 487 | + AscendC::RoundMode::CAST_ROUND, | ||
| 488 | + }; | ||
| 489 | + | ||
| 490 | + constexpr static CastTrait castTraitOneDown = { | ||
| 491 | + RegLayout::ONE, | ||
| 492 | + SatMode::SAT, | ||
| 493 | + MaskMergeMode::ZEROING, | ||
| 494 | + AscendC::RoundMode::CAST_ROUND, | ||
| 495 | + }; | ||
| 496 | + | ||
| 497 | + RegTensor<ElementInput> expVreg; | ||
| 498 | + RegTensor<float> expFloatVreg0; | ||
| 499 | + RegTensor<float> expFloatVreg1; | ||
| 500 | + RegTensor<float> expSumVreg; | ||
| 501 | + RegTensor<float> maxVreg; | ||
| 502 | + | ||
| 503 | + RegTensor<float> expDstFloatVreg0; | ||
| 504 | + RegTensor<float> expDstFloatVreg1; | ||
| 505 | + RegTensor<ElementInput> expDstVreg; | ||
| 506 | + RegTensor<ElementInput> expDstVreg0; | ||
| 507 | + RegTensor<ElementInput> expDstVreg1; | ||
| 508 | + | ||
| 509 | + UnalignReg expSumUreg; | ||
| 510 | + | ||
| 511 | + MaskReg pregFull = CreateMask<ElementInput, MaskPattern::ALL>(); | ||
| 512 | + MaskReg pregFloatFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 513 | + MaskReg pregTailN = UpdateMask<ElementInput>(tailN); | ||
| 514 | + MaskReg pregtailNOdd= UpdateMask<float>(tailNOdd); | ||
| 515 | + MaskReg pregtailNEven = UpdateMask<float>(tailNEven); | ||
| 516 | + for (uint16_t i = 0; i < m; ++i) { | ||
| 517 | + LoadAlign<float, LoadDist::DIST_BRC_B32>(maxVreg, nowMaxUb + i); | ||
| 518 | + Duplicate(expSumVreg, 0); | ||
| 519 | + LoadAlign(expVreg, srcUb + i * S2BaseSize); | ||
| 520 | + Cast<float, ElementInput, castTraitZero>(expFloatVreg0, expVreg, pregFull); | ||
| 521 | + Cast<float, ElementInput, castTraitOne>(expFloatVreg1, expVreg, pregFull); | ||
| 522 | + FusedExpSub(expDstFloatVreg0, expFloatVreg0, maxVreg, pregtailNEven); | ||
| 523 | + FusedExpSub(expDstFloatVreg1, expFloatVreg1, maxVreg, pregtailNOdd); | ||
| 524 | + Add<float, MaskMergeMode::MERGING>(expSumVreg, expSumVreg, expDstFloatVreg0, pregtailNEven); | ||
| 525 | + Add<float, MaskMergeMode::MERGING>(expSumVreg, expSumVreg, expDstFloatVreg1, pregtailNOdd); | ||
| 526 | + Cast<ElementInput, float, castTraitZeroDown>(expDstVreg0, expDstFloatVreg0, pregFloatFull); | ||
| 527 | + Cast<ElementInput, float, castTraitOneDown>(expDstVreg1, expDstFloatVreg1, pregFloatFull); | ||
| 528 | + Or((RegTensor<uint16_t>&)expDstVreg, | ||
| 529 | + (RegTensor<uint16_t>&)expDstVreg0, (RegTensor<uint16_t>&)expDstVreg1, | ||
| 530 | + pregFull); | ||
| 531 | + StoreAlign<ElementOutput, DataCopyMode::DATA_BLOCK_COPY>( | ||
| 532 | + expUb + i * ELE_NUM_PER_C0, | ||
| 533 | + expDstVreg, blockStride, pregTailN); | ||
| 534 | + ReduceSum(expSumVreg, expSumVreg, pregFull); | ||
| 535 | + StoreUnAlign<float, PostLiteral::POST_MODE_UPDATE>(expSumUb, expSumVreg, expSumUreg, 1); | ||
| 536 | + } | ||
| 537 | + vstas(expSumUreg, expSumUb, 0, POST_UPDATE); | ||
| 538 | + } | ||
| 539 | + | ||
| 540 | + template <> | ||
| 541 | + __simd_vf__ inline void ComputeExpSubSum16<KvBaseTileRegSplitStagesBf16::TWO>( | ||
| 542 | + __ubuf__ ElementOutput *expUb, __ubuf__ ElementInput *srcUb, | ||
| 543 | + __ubuf__ float *nowMaxUb, __ubuf__ float *expSumUb, | ||
| 544 | + uint16_t m, uint32_t tailN, uint32_t blockStride, | ||
| 545 | + uint16_t S2BaseSize, uint32_t tailNOdd, uint32_t tailNEven) | ||
| 546 | + { | ||
| 547 | + using namespace AscendC::MicroAPI; | ||
| 548 | + constexpr static CastTrait castTraitZero = { | ||
| 549 | + RegLayout::ZERO, | ||
| 550 | + SatMode::UNKNOWN, | ||
| 551 | + MaskMergeMode::ZEROING, | ||
| 552 | + AscendC::RoundMode::UNKNOWN, | ||
| 553 | + }; | ||
| 554 | + constexpr static CastTrait castTraitOne = { | ||
| 555 | + RegLayout::ONE, | ||
| 556 | + SatMode::UNKNOWN, | ||
| 557 | + MaskMergeMode::ZEROING, | ||
| 558 | + AscendC::RoundMode::UNKNOWN, | ||
| 559 | + }; | ||
| 560 | + | ||
| 561 | + constexpr static CastTrait castTraitZeroDown = { | ||
| 562 | + RegLayout::ZERO, | ||
| 563 | + SatMode::SAT, | ||
| 564 | + MaskMergeMode::ZEROING, | ||
| 565 | + AscendC::RoundMode::CAST_ROUND, | ||
| 566 | + }; | ||
| 567 | + | ||
| 568 | + constexpr static CastTrait castTraitOneDown = { | ||
| 569 | + RegLayout::ONE, | ||
| 570 | + SatMode::SAT, | ||
| 571 | + MaskMergeMode::ZEROING, | ||
| 572 | + AscendC::RoundMode::CAST_ROUND, | ||
| 573 | + }; | ||
| 574 | + | ||
| 575 | + RegTensor<ElementInput> expVreg0; | ||
| 576 | + RegTensor<ElementInput> expVreg1; | ||
| 577 | + RegTensor<float> expFloatVreg0; | ||
| 578 | + RegTensor<float> expFloatVreg1; | ||
| 579 | + RegTensor<float> expFloatVreg2; | ||
| 580 | + RegTensor<float> expFloatVreg3; | ||
| 581 | + RegTensor<float> expSumVreg; | ||
| 582 | + RegTensor<float> maxVreg; | ||
| 583 | + | ||
| 584 | + RegTensor<float> expDstFloatVreg0; | ||
| 585 | + RegTensor<float> expDstFloatVreg1; | ||
| 586 | + RegTensor<float> expDstFloatVreg2; | ||
| 587 | + RegTensor<float> expDstFloatVreg3; | ||
| 588 | + RegTensor<ElementInput> expOutVreg0; | ||
| 589 | + RegTensor<ElementInput> expOutVreg1; | ||
| 590 | + RegTensor<ElementInput> expDstVreg0; | ||
| 591 | + RegTensor<ElementInput> expDstVreg1; | ||
| 592 | + RegTensor<ElementInput> expDstVreg2; | ||
| 593 | + RegTensor<ElementInput> expDstVreg3; | ||
| 594 | + | ||
| 595 | + UnalignReg expSumUreg; | ||
| 596 | + | ||
| 597 | + MaskReg pregFull = CreateMask<ElementInput, MaskPattern::ALL>(); | ||
| 598 | + MaskReg pregFloatFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 599 | + MaskReg pregTailN = UpdateMask<ElementInput>(tailN); | ||
| 600 | + MaskReg pregtailNOdd= UpdateMask<float>(tailNOdd); | ||
| 601 | + MaskReg pregtailNEven = UpdateMask<float>(tailNEven); | ||
| 602 | + for (uint16_t i = 0; i < m; ++i) { | ||
| 603 | + LoadAlign<float, LoadDist::DIST_BRC_B32>(maxVreg, nowMaxUb + i); | ||
| 604 | + Duplicate(expSumVreg, 0); | ||
| 605 | + LoadAlign(expVreg0, srcUb + i * S2BaseSize); | ||
| 606 | + LoadAlign(expVreg1, srcUb + i * S2BaseSize + HALF_REP_SIZE); | ||
| 607 | + Cast<float, ElementInput, castTraitZero>(expFloatVreg0, expVreg0, pregFull); | ||
| 608 | + Cast<float, ElementInput, castTraitOne>(expFloatVreg1, expVreg0, pregFull); | ||
| 609 | + Cast<float, ElementInput, castTraitZero>(expFloatVreg2, expVreg1, pregFull); | ||
| 610 | + Cast<float, ElementInput, castTraitOne>(expFloatVreg3, expVreg1, pregFull); | ||
| 611 | + FusedExpSub(expDstFloatVreg0, expFloatVreg0, maxVreg, pregFloatFull); | ||
| 612 | + FusedExpSub(expDstFloatVreg1, expFloatVreg1, maxVreg, pregFloatFull); | ||
| 613 | + FusedExpSub(expDstFloatVreg2, expFloatVreg2, maxVreg, pregtailNEven); | ||
| 614 | + FusedExpSub(expDstFloatVreg3, expFloatVreg3, maxVreg, pregtailNOdd); | ||
| 615 | + Add<float, MaskMergeMode::MERGING>(expSumVreg, expSumVreg, expDstFloatVreg0, pregFloatFull); | ||
| 616 | + Add<float, MaskMergeMode::MERGING>(expSumVreg, expSumVreg, expDstFloatVreg1, pregFloatFull); | ||
| 617 | + Add<float, MaskMergeMode::MERGING>(expSumVreg, expSumVreg, expDstFloatVreg2, pregtailNEven); | ||
| 618 | + Add<float, MaskMergeMode::MERGING>(expSumVreg, expSumVreg, expDstFloatVreg3, pregtailNOdd); | ||
| 619 | + Cast<ElementInput, float, castTraitZeroDown>(expDstVreg0, expDstFloatVreg0, pregFloatFull); | ||
| 620 | + Cast<ElementInput, float, castTraitOneDown>(expDstVreg1, expDstFloatVreg1, pregFloatFull); | ||
| 621 | + Cast<ElementInput, float, castTraitZeroDown>(expDstVreg2, expDstFloatVreg2, pregFloatFull); | ||
| 622 | + Cast<ElementInput, float, castTraitOneDown>(expDstVreg3, expDstFloatVreg3, pregFloatFull); | ||
| 623 | + Or((RegTensor<uint16_t>&)expOutVreg0, | ||
| 624 | + (RegTensor<uint16_t>&)expDstVreg0, (RegTensor<uint16_t>&)expDstVreg1, | ||
| 625 | + pregFull); | ||
| 626 | + Or((RegTensor<uint16_t>&)expOutVreg1, | ||
| 627 | + (RegTensor<uint16_t>&)expDstVreg2, (RegTensor<uint16_t>&)expDstVreg3, | ||
| 628 | + pregFull); | ||
| 629 | + StoreAlign<ElementOutput, DataCopyMode::DATA_BLOCK_COPY>( | ||
| 630 | + expUb + i * ELE_NUM_PER_C0, | ||
| 631 | + expOutVreg0, blockStride, pregFull); | ||
| 632 | + StoreAlign<ElementOutput, DataCopyMode::DATA_BLOCK_COPY>( | ||
| 633 | + expUb + i * ELE_NUM_PER_C0 + blockStride * ELE_NUM_PER_C0 * BLOCK_REP_SIZE, | ||
| 634 | + expOutVreg1, blockStride, pregTailN); | ||
| 635 | + | ||
| 636 | + ReduceSum(expSumVreg, expSumVreg, pregFull); | ||
| 637 | + StoreUnAlign<float, PostLiteral::POST_MODE_UPDATE>(expSumUb, expSumVreg, expSumUreg, 1); | ||
| 638 | + } | ||
| 639 | + vstas(expSumUreg, expSumUb, 0, POST_UPDATE); | ||
| 640 | + } | ||
| 641 | + | ||
| 642 | + __simd_vf__ inline void UpdateExpSumAndExpMax(__ubuf__ float *sumUb, __ubuf__ float *expMaxUb, | ||
| 643 | + __ubuf__ float *maxUb, __ubuf__ float *expSumUb, __ubuf__ float *nowMaxUb, | ||
| 644 | + uint16_t mLoops, uint32_t tailM) | ||
| 645 | + { | ||
| 646 | + using namespace AscendC::MicroAPI; | ||
| 647 | + | ||
| 648 | + RegTensor<float> nowMaxFloatVreg; | ||
| 649 | + RegTensor<float> lastMaxVreg; | ||
| 650 | + RegTensor<float> expMaxVreg; | ||
| 651 | + RegTensor<float> lastExpSumVreg; | ||
| 652 | + RegTensor<float> brcExpSumFloatVreg; | ||
| 653 | + RegTensor<float> updateExpSumVreg; | ||
| 654 | + MaskReg pregFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 655 | + MaskReg pregTailM = UpdateMask<float>(tailM); | ||
| 656 | + for (int16_t i = 0; i < mLoops; ++i) { | ||
| 657 | + LoadAlign(lastMaxVreg, maxUb + i * FLOAT_REP_SIZE); | ||
| 658 | + LoadAlign(nowMaxFloatVreg, nowMaxUb + i * FLOAT_REP_SIZE); | ||
| 659 | + FusedExpSub(expMaxVreg, lastMaxVreg, nowMaxFloatVreg, pregFull); | ||
| 660 | + StoreAlign<float, StoreDist::DIST_NORM_B32>(expMaxUb + i * FLOAT_REP_SIZE, expMaxVreg, pregFull); | ||
| 661 | + StoreAlign<float, StoreDist::DIST_NORM_B32>(maxUb + i * FLOAT_REP_SIZE, nowMaxFloatVreg, pregFull); | ||
| 662 | + | ||
| 663 | + LoadAlign(lastExpSumVreg, sumUb + i * FLOAT_REP_SIZE); | ||
| 664 | + LoadAlign(brcExpSumFloatVreg, expSumUb + i * FLOAT_REP_SIZE); | ||
| 665 | + Mul(updateExpSumVreg, expMaxVreg, lastExpSumVreg, pregFull); | ||
| 666 | + Add(updateExpSumVreg, updateExpSumVreg, brcExpSumFloatVreg, pregFull); | ||
| 667 | + StoreAlign<float, StoreDist::DIST_NORM_B32>(sumUb + i * FLOAT_REP_SIZE, updateExpSumVreg, pregFull); | ||
| 668 | + } | ||
| 669 | + LoadAlign(lastMaxVreg, maxUb + mLoops * FLOAT_REP_SIZE); | ||
| 670 | + LoadAlign(nowMaxFloatVreg, nowMaxUb + mLoops * FLOAT_REP_SIZE); | ||
| 671 | + FusedExpSub(expMaxVreg, lastMaxVreg, nowMaxFloatVreg, pregTailM); | ||
| 672 | + StoreAlign<float, StoreDist::DIST_NORM_B32>(expMaxUb + mLoops * FLOAT_REP_SIZE, expMaxVreg, pregTailM); | ||
| 673 | + StoreAlign<float, StoreDist::DIST_NORM_B32>(maxUb + mLoops * FLOAT_REP_SIZE, nowMaxFloatVreg, pregTailM); | ||
| 674 | + | ||
| 675 | + LoadAlign(lastExpSumVreg, sumUb + mLoops * FLOAT_REP_SIZE); | ||
| 676 | + LoadAlign(brcExpSumFloatVreg, expSumUb + mLoops * FLOAT_REP_SIZE); | ||
| 677 | + Mul(updateExpSumVreg, expMaxVreg, lastExpSumVreg, pregTailM); | ||
| 678 | + Add(updateExpSumVreg, updateExpSumVreg, brcExpSumFloatVreg, pregTailM); | ||
| 679 | + StoreAlign<float, StoreDist::DIST_NORM_B32>(sumUb + mLoops * FLOAT_REP_SIZE, updateExpSumVreg, pregTailM); | ||
| 680 | + } | ||
| 681 | +}; | ||
| 682 | +} | ||
| 683 | + | ||
| 684 | + | ||
| @@ -0,0 +1,983 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +namespace NpuArch::Epilogue::Block { | ||
| 23 | + | ||
| 24 | +template < | ||
| 25 | + class OutputType_, | ||
| 26 | + class InputType_, | ||
| 27 | + class MaskType_, | ||
| 28 | + LseMode LSE_MODE_> | ||
| 29 | +class BlockEpilogue< | ||
| 30 | + EpilogueAtlasA2OnlineSoftmax<LSE_MODE_, half>, | ||
| 31 | + OutputType_, | ||
| 32 | + InputType_, | ||
| 33 | + MaskType_> | ||
| 34 | +{ | ||
| 35 | +public: | ||
| 36 | + using DispatchPolicy = EpilogueAtlasA2OnlineSoftmax<LSE_MODE_, half>; | ||
| 37 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 38 | + using ElementOutput = typename OutputType_::Element; | ||
| 39 | + using ElementInput = typename InputType_::Element; | ||
| 40 | + using ElementMask = typename MaskType_::Element; | ||
| 41 | + | ||
| 42 | + using LayoutOutput = typename OutputType_::Layout; | ||
| 43 | + using LayoutInput = typename InputType_::Layout; | ||
| 44 | + using LayoutMask = typename MaskType_::Layout; | ||
| 45 | + | ||
| 46 | + static constexpr LseMode LSE_MODE = DispatchPolicy::LSE_MODE; | ||
| 47 | + | ||
| 48 | + static constexpr uint32_t BLOCK_SIZE_IN_BYTE = 32; | ||
| 49 | + static constexpr uint32_t REPEAT_SIZE_IN_BYTE = 256; | ||
| 50 | + static constexpr uint32_t FLOAT_BLOCK_SIZE = 8; | ||
| 51 | + static constexpr uint32_t FLOAT_VECTOR_SIZE = 64; | ||
| 52 | + static constexpr uint32_t HALF_VECTOR_SIZE = 128; | ||
| 53 | + static constexpr uint32_t BLOCK_SIZE = 16; | ||
| 54 | + static constexpr uint32_t UB_UINT8_VECTOR_SIZE = 1024; | ||
| 55 | + static constexpr uint32_t UB_UINT8_BLOCK_SIZE = 16384; | ||
| 56 | + static constexpr uint32_t VECTOR_SIZE = 128; | ||
| 57 | + static constexpr uint32_t MAX_UB_S_ELEM_NUM = 16384; | ||
| 58 | + | ||
| 59 | + static constexpr uint32_t REDUCE_UB_SIZE = 1024; | ||
| 60 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_32 = 32; | ||
| 61 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_8 = 8; | ||
| 62 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_4 = 4; | ||
| 63 | + static constexpr uint32_t ROW_OPS_SPEC_MASK_2 = 2; | ||
| 64 | + static constexpr uint32_t MAX_ROW_NUM_SUB_CORE = 256; | ||
| 65 | + static constexpr int64_t UB_FLOAT_LINE_SIZE = 64; | ||
| 66 | + | ||
| 67 | + static constexpr uint32_t SPLIT_COL_IDX_2 = 2; | ||
| 68 | + static constexpr uint32_t SPLIT_COL_IDX_3 = 3; | ||
| 69 | + __aicore__ inline | ||
| 70 | + BlockEpilogue(Arch::Resource<ArchTag> &resource, float scaleValue_) | ||
| 71 | + { | ||
| 72 | + // Allocate UB space | ||
| 73 | + constexpr uint32_t LS_UB_TENSOR_OFFSET = 0; | ||
| 74 | + constexpr uint32_t COMPUTE_UB_TENSOR_OFFSET = 2 * UB_UINT8_BLOCK_SIZE; | ||
| 75 | + constexpr uint32_t LP_UB_TENSOR_OFFSET = 4 * UB_UINT8_BLOCK_SIZE; | ||
| 76 | + constexpr uint32_t MASK16_UB_TENSOR_OFFSET = 0; | ||
| 77 | + | ||
| 78 | + constexpr uint32_t TV_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE; | ||
| 79 | + constexpr uint32_t LM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 8 * UB_UINT8_VECTOR_SIZE; | ||
| 80 | + | ||
| 81 | + constexpr uint32_t HM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 9 * UB_UINT8_VECTOR_SIZE; | ||
| 82 | + constexpr uint32_t GM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 10 * UB_UINT8_VECTOR_SIZE; | ||
| 83 | + constexpr uint32_t LL_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 11 * UB_UINT8_VECTOR_SIZE; | ||
| 84 | + constexpr uint32_t GL_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 12 * UB_UINT8_VECTOR_SIZE; | ||
| 85 | + constexpr uint32_t DM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 13 * UB_UINT8_VECTOR_SIZE; | ||
| 86 | + | ||
| 87 | + constexpr uint32_t MASK_UB_TENSOR_OFFSET = 11 * UB_UINT8_BLOCK_SIZE; | ||
| 88 | + | ||
| 89 | + scaleValue = static_cast<half>(scaleValue_); | ||
| 90 | + lsUbTensor = resource.ubBuf.template GetBufferByByte<half>(LS_UB_TENSOR_OFFSET); | ||
| 91 | + computeUbTensor = resource.ubBuf.template GetBufferByByte<half>(COMPUTE_UB_TENSOR_OFFSET); | ||
| 92 | + lpUbTensor = resource.ubBuf.template GetBufferByByte<ElementOutput>(LP_UB_TENSOR_OFFSET); | ||
| 93 | + maskUbTensor = resource.ubBuf.template GetBufferByByte<ElementMask>(MASK_UB_TENSOR_OFFSET); | ||
| 94 | + maskUbTensor16 = resource.ubBuf.template GetBufferByByte<half>(MASK16_UB_TENSOR_OFFSET); | ||
| 95 | + lmUbTensor = resource.ubBuf.template GetBufferByByte<half>(LM_UB_TENSOR_OFFSET); | ||
| 96 | + hmUbTensor = resource.ubBuf.template GetBufferByByte<half>(HM_UB_TENSOR_OFFSET); | ||
| 97 | + gmUbTensor = resource.ubBuf.template GetBufferByByte<half>(GM_UB_TENSOR_OFFSET); | ||
| 98 | + dmUbTensor = resource.ubBuf.template GetBufferByByte<half>(DM_UB_TENSOR_OFFSET); | ||
| 99 | + llUbTensor = resource.ubBuf.template GetBufferByByte<half>(LL_UB_TENSOR_OFFSET); | ||
| 100 | + tvUbTensor = resource.ubBuf.template GetBufferByByte<half>(TV_UB_TENSOR_OFFSET); | ||
| 101 | + glUbTensor = resource.ubBuf.template GetBufferByByte<half>(GL_UB_TENSOR_OFFSET); | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + __aicore__ inline | ||
| 105 | + ~BlockEpilogue() {} | ||
| 106 | + | ||
| 107 | + __aicore__ inline | ||
| 108 | + void SetVecMask(int32_t len) | ||
| 109 | + { | ||
| 110 | + const int32_t MAX_MASK_LEN = 128; | ||
| 111 | + const int32_t HALF_MASK_LEN = 64; | ||
| 112 | + if (len >= MAX_MASK_LEN) { | ||
| 113 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 114 | + return; | ||
| 115 | + } | ||
| 116 | + int32_t highMask = len - HALF_MASK_LEN > 0 ? len - HALF_MASK_LEN : 0; | ||
| 117 | + int32_t lowMask = len - HALF_MASK_LEN >= 0 ? HALF_MASK_LEN : len; | ||
| 118 | + if (len < HALF_MASK_LEN) { | ||
| 119 | + AscendC::SetVectorMask<int8_t>(0x0, ((uint64_t)1 << lowMask) - 1); | ||
| 120 | + } else { | ||
| 121 | + AscendC::SetVectorMask<int8_t>(((uint64_t)1 << highMask) - 1, 0xffffffffffffffff); | ||
| 122 | + } | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + __aicore__ inline | ||
| 126 | + void SetBlockReduceMask(int32_t len) | ||
| 127 | + { | ||
| 128 | + const int32_t MAX_LEN = 16; | ||
| 129 | + if (len > MAX_LEN) { | ||
| 130 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 131 | + return; | ||
| 132 | + } | ||
| 133 | + uint64_t subMask = (static_cast<uint64_t>(1) << len) - 1; | ||
| 134 | + uint64_t maskValue = (subMask << 48) + (subMask << 32) + (subMask << 16) + subMask; | ||
| 135 | + AscendC::SetVectorMask<int8_t>(maskValue, maskValue); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + __aicore__ inline | ||
| 139 | + void ReduceSumByPair(const AscendC::LocalTensor<half> &srcUb, uint32_t numRowsRound, uint32_t loopCount, | ||
| 140 | + uint32_t columnStrideIndex, uint8_t dataBlockStride, uint8_t repeatStride) | ||
| 141 | + { | ||
| 142 | + for (uint32_t i = 0; i < loopCount; i += columnStrideIndex) { | ||
| 143 | + uint32_t src0Start = i * HALF_VECTOR_SIZE; | ||
| 144 | + uint32_t src1Start = (i + columnStrideIndex / 2) * HALF_VECTOR_SIZE; | ||
| 145 | + AscendC::Add<half, false>( | ||
| 146 | + srcUb[src0Start], | ||
| 147 | + srcUb[src0Start], | ||
| 148 | + srcUb[src1Start], | ||
| 149 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 150 | + numRowsRound, | ||
| 151 | + AscendC::BinaryRepeatParams( | ||
| 152 | + dataBlockStride, | ||
| 153 | + dataBlockStride, | ||
| 154 | + dataBlockStride, | ||
| 155 | + repeatStride, | ||
| 156 | + repeatStride, | ||
| 157 | + repeatStride)); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + __aicore__ inline | ||
| 162 | + void RowsumTileFlexible(const AscendC::LocalTensor<half> &srcUb, const AscendC::LocalTensor<half> &rowsumUb, | ||
| 163 | + uint32_t numRowsRound, uint32_t numElemsAligned) | ||
| 164 | + { | ||
| 165 | + // Vector计算单元每个迭代最多处理256Byte数据,因此half低精度场景,每次迭代最多处理256/2=128个元素 | ||
| 166 | + uint32_t loopCount = numElemsAligned / HALF_VECTOR_SIZE; // half低精度场景,每行需要numElemsAligned/128次循环处理 | ||
| 167 | + // 每个datablock长度32Byte,因此half低精度场景,每个datablock内有32/2=16个元素 | ||
| 168 | + uint8_t dataBlockNumPerRow = numElemsAligned / BLOCK_SIZE; // half低精度场景,每行共有numElemsAligned/16个datablock | ||
| 169 | + uint8_t dataBlockStride = 1; | ||
| 170 | + | ||
| 171 | + // 举例,若numElemsAligned为1024,以128为单位分治求和,1024->512->256->128 | ||
| 172 | + for (uint32_t columnStrideIndex = 2; columnStrideIndex <= loopCount; columnStrideIndex *= 2) { | ||
| 173 | + ReduceSumByPair(srcUb, numRowsRound, loopCount, columnStrideIndex, dataBlockStride, dataBlockNumPerRow); | ||
| 174 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + //每行128个元素分别规约求和 | ||
| 178 | + AscendC::WholeReduceSum<half, false>( | ||
| 179 | + rowsumUb, | ||
| 180 | + srcUb, | ||
| 181 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 182 | + numRowsRound, | ||
| 183 | + dataBlockStride, | ||
| 184 | + dataBlockStride, | ||
| 185 | + dataBlockNumPerRow); | ||
| 186 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + __aicore__ inline | ||
| 190 | + void RowsumSPECTILE1024(const AscendC::LocalTensor<half> &srcUb, const AscendC::LocalTensor<half> &rowsumUb, | ||
| 191 | + const AscendC::LocalTensor<half> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 192 | + uint32_t numElemsAligned) | ||
| 193 | + { | ||
| 194 | + RowsumTileFlexible(srcUb, rowsumUb, numRowsRound, numElemsAligned); | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + __aicore__ inline | ||
| 198 | + void RowsumSPECTILE512(const AscendC::LocalTensor<half> &srcUb, const AscendC::LocalTensor<half> &rowsumUb, | ||
| 199 | + const AscendC::LocalTensor<half> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 200 | + uint32_t numElemsAligned) | ||
| 201 | + { | ||
| 202 | + RowsumTileFlexible(srcUb, rowsumUb, numRowsRound, numElemsAligned); | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + __aicore__ inline | ||
| 206 | + void RowsumTAILTILE(const AscendC::LocalTensor<half> &srcUb, const AscendC::LocalTensor<half> &rowsumUb, | ||
| 207 | + const AscendC::LocalTensor<half> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 208 | + uint32_t numElemsAligned) | ||
| 209 | + { | ||
| 210 | + if (numElems <= HALF_VECTOR_SIZE) { | ||
| 211 | + SetVecMask(numElems); | ||
| 212 | + AscendC::WholeReduceSum<half, false>( | ||
| 213 | + rowsumUb, srcUb, (int32_t)0, numRowsRound, 1, 1, | ||
| 214 | + numElemsAligned / BLOCK_SIZE); | ||
| 215 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 216 | + } else { | ||
| 217 | + for (uint32_t vmaxIdx = 1; vmaxIdx < numElems / HALF_VECTOR_SIZE; vmaxIdx++) { | ||
| 218 | + AscendC::Add<half, false>( | ||
| 219 | + srcUb, | ||
| 220 | + srcUb, | ||
| 221 | + srcUb[vmaxIdx * HALF_VECTOR_SIZE], | ||
| 222 | + (uint64_t)0, | ||
| 223 | + numRowsRound, | ||
| 224 | + AscendC::BinaryRepeatParams( | ||
| 225 | + 1, 1, 1, | ||
| 226 | + numElemsAligned / BLOCK_SIZE, | ||
| 227 | + numElemsAligned / BLOCK_SIZE, | ||
| 228 | + numElemsAligned / BLOCK_SIZE)); | ||
| 229 | + } | ||
| 230 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 231 | + if (numElems % HALF_VECTOR_SIZE > 0) { | ||
| 232 | + SetVecMask(numElems % HALF_VECTOR_SIZE); | ||
| 233 | + AscendC::Add<half, false>( | ||
| 234 | + srcUb, | ||
| 235 | + srcUb, | ||
| 236 | + srcUb[numElems / HALF_VECTOR_SIZE * HALF_VECTOR_SIZE], | ||
| 237 | + (uint64_t)0, | ||
| 238 | + numRowsRound, | ||
| 239 | + AscendC::BinaryRepeatParams( | ||
| 240 | + 1, 1, 1, | ||
| 241 | + numElemsAligned / BLOCK_SIZE, | ||
| 242 | + numElemsAligned / BLOCK_SIZE, | ||
| 243 | + numElemsAligned / BLOCK_SIZE)); | ||
| 244 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 245 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 246 | + } | ||
| 247 | + AscendC::WholeReduceSum<half, false>( | ||
| 248 | + rowsumUb, srcUb, (int32_t)0, numRowsRound, 1, 1, | ||
| 249 | + numElemsAligned / BLOCK_SIZE); | ||
| 250 | + } | ||
| 251 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + __aicore__ inline | ||
| 255 | + void ReduceMaxByPair(const AscendC::LocalTensor<half> &dstUb, const AscendC::LocalTensor<half> &srcUb, | ||
| 256 | + uint32_t numRowsRound, uint32_t loopCount, uint32_t columnStrideIndex, | ||
| 257 | + uint8_t dataBlockStride, uint8_t repeatStride) | ||
| 258 | + { | ||
| 259 | + for (uint32_t i = 0; i < loopCount; i += columnStrideIndex) { | ||
| 260 | + uint32_t src0Start = i * HALF_VECTOR_SIZE; | ||
| 261 | + uint32_t src1Start = (i + columnStrideIndex / 2) * HALF_VECTOR_SIZE; | ||
| 262 | + AscendC::Max<half, false>( | ||
| 263 | + dstUb[src0Start], | ||
| 264 | + srcUb[src0Start], | ||
| 265 | + srcUb[src1Start], | ||
| 266 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 267 | + numRowsRound, | ||
| 268 | + AscendC::BinaryRepeatParams( | ||
| 269 | + dataBlockStride, | ||
| 270 | + dataBlockStride, | ||
| 271 | + dataBlockStride, | ||
| 272 | + repeatStride, | ||
| 273 | + repeatStride, | ||
| 274 | + repeatStride)); | ||
| 275 | + } | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + __aicore__ inline | ||
| 279 | + void RowmaxTileFlexible(const AscendC::LocalTensor<half> &srcUb, const AscendC::LocalTensor<half> &rowmaxUb, | ||
| 280 | + uint32_t numRowsRound, uint32_t numElemsAligned) | ||
| 281 | + { | ||
| 282 | + // Vector计算单元每个迭代最多处理256Byte数据,因此half低精度场景,每次迭代最多处理256/2=128个元素 | ||
| 283 | + uint32_t loopCount = numElemsAligned / HALF_VECTOR_SIZE; // half低精度场景,每行需要numElemsAligned/128次循环处理 | ||
| 284 | + // 每个datablock长度32Byte,因此half低精度场景,每个datablock内有32/2=16个元素 | ||
| 285 | + uint8_t dataBlockNumPerRow = numElemsAligned / BLOCK_SIZE; // half低精度场景,每行共有numElemsAligned/16个datablock | ||
| 286 | + uint8_t dataBlockStride = 1; | ||
| 287 | + | ||
| 288 | + // 举例,若numElemsAligned为1024,以128为单位分治求最大值,1024->512->256->128 | ||
| 289 | + uint32_t columnStrideIndex = 2; | ||
| 290 | + // 后续Rowsum计算还会使用到srcUb,因此第一轮分治使用lsUbTensor作为目的操作数,srcUb作为源操作数 | ||
| 291 | + ReduceMaxByPair(lsUbTensor, srcUb, numRowsRound, loopCount, columnStrideIndex, dataBlockStride, dataBlockNumPerRow); | ||
| 292 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 293 | + columnStrideIndex *= 2; | ||
| 294 | + for (; columnStrideIndex <= loopCount; columnStrideIndex *= 2) { | ||
| 295 | + ReduceMaxByPair(lsUbTensor, lsUbTensor, numRowsRound, loopCount, columnStrideIndex, dataBlockStride, dataBlockNumPerRow); | ||
| 296 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 297 | + } | ||
| 298 | + | ||
| 299 | + //每行128个元素分别规约求最大值 | ||
| 300 | + AscendC::WholeReduceMax<half, false>( | ||
| 301 | + rowmaxUb, | ||
| 302 | + lsUbTensor, | ||
| 303 | + AscendC::MASK_PLACEHOLDER, // (uint64_t)0 | ||
| 304 | + numRowsRound, | ||
| 305 | + dataBlockStride, | ||
| 306 | + dataBlockStride, | ||
| 307 | + dataBlockNumPerRow, | ||
| 308 | + AscendC::ReduceOrder::ORDER_ONLY_VALUE); | ||
| 309 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 310 | + } | ||
| 311 | + | ||
| 312 | + __aicore__ inline | ||
| 313 | + void RowmaxSPECTILE1024(const AscendC::LocalTensor<half> &srcUb, const AscendC::LocalTensor<half> &rowmaxUb, | ||
| 314 | + const AscendC::LocalTensor<half> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 315 | + uint32_t numElemsAligned) | ||
| 316 | + { | ||
| 317 | + RowmaxTileFlexible(srcUb, rowmaxUb, numRowsRound, numElemsAligned); | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + __aicore__ inline | ||
| 321 | + void RowmaxSPECTILE512(const AscendC::LocalTensor<half> &srcUb, const AscendC::LocalTensor<half> &rowmaxUb, | ||
| 322 | + const AscendC::LocalTensor<half> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 323 | + uint32_t numElemsAligned) | ||
| 324 | + { | ||
| 325 | + RowmaxTileFlexible(srcUb, rowmaxUb, numRowsRound, numElemsAligned); | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + __aicore__ inline | ||
| 329 | + void RowmaxTAILTILE(const AscendC::LocalTensor<half> &srcUb, const AscendC::LocalTensor<half> &rowmaxUb, | ||
| 330 | + const AscendC::LocalTensor<half> &tvUbTensor, uint32_t numRowsRound, uint32_t numElems, | ||
| 331 | + uint32_t numElemsAligned) | ||
| 332 | + { | ||
| 333 | + if (numElems <= HALF_VECTOR_SIZE) { | ||
| 334 | + SetVecMask(numElems); | ||
| 335 | + AscendC::WholeReduceMax<half, false>( | ||
| 336 | + rowmaxUb, srcUb, (int32_t)0, numRowsRound, 1, 1, | ||
| 337 | + numElemsAligned / BLOCK_SIZE, AscendC::ReduceOrder::ORDER_ONLY_VALUE); | ||
| 338 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 339 | + } else { | ||
| 340 | + AscendC::DataCopy( | ||
| 341 | + lsUbTensor, | ||
| 342 | + srcUb, | ||
| 343 | + AscendC::DataCopyParams( | ||
| 344 | + numRowsRound, | ||
| 345 | + HALF_VECTOR_SIZE / BLOCK_SIZE, | ||
| 346 | + (numElemsAligned - HALF_VECTOR_SIZE) / BLOCK_SIZE, | ||
| 347 | + (numElemsAligned - HALF_VECTOR_SIZE) / BLOCK_SIZE)); | ||
| 348 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 349 | + for (uint32_t vmaxIdx = 1; vmaxIdx < numElems / HALF_VECTOR_SIZE; vmaxIdx++) { | ||
| 350 | + AscendC::Max<half, false>( | ||
| 351 | + lsUbTensor, | ||
| 352 | + lsUbTensor, | ||
| 353 | + srcUb[vmaxIdx * HALF_VECTOR_SIZE], | ||
| 354 | + (uint64_t)0, | ||
| 355 | + numRowsRound, | ||
| 356 | + AscendC::BinaryRepeatParams( | ||
| 357 | + 1, 1, 1, | ||
| 358 | + numElemsAligned / BLOCK_SIZE, | ||
| 359 | + numElemsAligned / BLOCK_SIZE, | ||
| 360 | + numElemsAligned / BLOCK_SIZE)); | ||
| 361 | + } | ||
| 362 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 363 | + if (numElems % HALF_VECTOR_SIZE > 0) { | ||
| 364 | + SetVecMask(numElems % HALF_VECTOR_SIZE); | ||
| 365 | + AscendC::Max<half, false>( | ||
| 366 | + lsUbTensor, | ||
| 367 | + lsUbTensor, | ||
| 368 | + srcUb[numElems / HALF_VECTOR_SIZE * HALF_VECTOR_SIZE], | ||
| 369 | + (uint64_t)0, | ||
| 370 | + numRowsRound, | ||
| 371 | + AscendC::BinaryRepeatParams( | ||
| 372 | + 1, 1, 1, | ||
| 373 | + numElemsAligned / BLOCK_SIZE, | ||
| 374 | + numElemsAligned / BLOCK_SIZE, | ||
| 375 | + numElemsAligned / BLOCK_SIZE)); | ||
| 376 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 377 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 378 | + } | ||
| 379 | + AscendC::WholeReduceMax<half, false>( | ||
| 380 | + rowmaxUb, lsUbTensor, (int32_t)0, numRowsRound, 1, 1, | ||
| 381 | + numElemsAligned / BLOCK_SIZE, AscendC::ReduceOrder::ORDER_ONLY_VALUE); | ||
| 382 | + } | ||
| 383 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 384 | + } | ||
| 385 | + | ||
| 386 | + __aicore__ inline | ||
| 387 | + void CopySGmToUb(AscendC::GlobalTensor<half> gInput, uint32_t sUbOffset, uint32_t rowNumCurLoop, | ||
| 388 | + uint32_t columnNumRound, uint32_t columnNumPad) | ||
| 389 | + { | ||
| 390 | + // input S | ||
| 391 | + AscendC::DataCopy( | ||
| 392 | + lsUbTensor, | ||
| 393 | + gInput, | ||
| 394 | + AscendC::DataCopyParams(rowNumCurLoop, | ||
| 395 | + columnNumRound / BLOCK_SIZE, | ||
| 396 | + (columnNumPad - columnNumRound) / BLOCK_SIZE, | ||
| 397 | + 0)); | ||
| 398 | + } | ||
| 399 | + | ||
| 400 | + __aicore__ inline | ||
| 401 | + void CopyMaskGmToUb(AscendC::GlobalTensor<ElementMask> gMask, uint32_t columnNum, uint32_t columnNumRound, | ||
| 402 | + uint32_t maskStride, uint32_t tokenNumPerHead, uint32_t proTokenIdx, uint32_t proTokenNum, | ||
| 403 | + uint32_t integralHeadNum, uint32_t epiTokenNum) | ||
| 404 | + { | ||
| 405 | + uint32_t innerUbRowOffset = 0; | ||
| 406 | + if (proTokenNum != 0U) { | ||
| 407 | + AscendC::DataCopyPad( | ||
| 408 | + maskUbTensor[innerUbRowOffset], | ||
| 409 | + gMask[proTokenIdx * maskStride], | ||
| 410 | + AscendC::DataCopyExtParams( | ||
| 411 | + proTokenNum, columnNum * sizeof(ElementMask), | ||
| 412 | + (maskStride - columnNum) * sizeof(ElementMask), 0, 0), | ||
| 413 | + AscendC::DataCopyPadExtParams<ElementMask>(false, 0, 0, 0)); | ||
| 414 | + innerUbRowOffset += proTokenNum * columnNumRound; | ||
| 415 | + } | ||
| 416 | + for (uint32_t headIdx = 0; headIdx < integralHeadNum; headIdx++) { | ||
| 417 | + AscendC::DataCopyPad( | ||
| 418 | + maskUbTensor[innerUbRowOffset], | ||
| 419 | + gMask, | ||
| 420 | + AscendC::DataCopyExtParams( | ||
| 421 | + tokenNumPerHead, columnNum * sizeof(ElementMask), | ||
| 422 | + (maskStride - columnNum) * sizeof(ElementMask), 0, 0), | ||
| 423 | + AscendC::DataCopyPadExtParams<ElementMask>(false, 0, 0, 0)); | ||
| 424 | + innerUbRowOffset += tokenNumPerHead * columnNumRound; | ||
| 425 | + } | ||
| 426 | + if (epiTokenNum != 0) { | ||
| 427 | + AscendC::DataCopyPad( | ||
| 428 | + maskUbTensor[innerUbRowOffset], | ||
| 429 | + gMask, | ||
| 430 | + AscendC::DataCopyExtParams( | ||
| 431 | + epiTokenNum, columnNum * sizeof(ElementMask), | ||
| 432 | + (maskStride - columnNum) * sizeof(ElementMask), 0, 0), | ||
| 433 | + AscendC::DataCopyPadExtParams<ElementMask>(false, 0, 0, 0)); | ||
| 434 | + } | ||
| 435 | + } | ||
| 436 | + | ||
| 437 | + __aicore__ inline | ||
| 438 | + void ScaleS(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t columnNumRound) | ||
| 439 | + { | ||
| 440 | + // *** ls = scaleValue * ls | ||
| 441 | + AscendC::Muls<half, false>( | ||
| 442 | + computeUbTensor, | ||
| 443 | + lsUbTensor, | ||
| 444 | + scaleValue, | ||
| 445 | + (uint64_t)0, | ||
| 446 | + (rowNumCurLoop * columnNumRound + HALF_VECTOR_SIZE - 1) / HALF_VECTOR_SIZE, | ||
| 447 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 448 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 449 | + } | ||
| 450 | + | ||
| 451 | + template<typename ElementMaskDst, typename ElementMaskSrc> | ||
| 452 | + __aicore__ inline | ||
| 453 | + void UpCastMask( | ||
| 454 | + const AscendC::LocalTensor<ElementMaskDst> &maskUbTensorDst, | ||
| 455 | + const AscendC::LocalTensor<ElementMaskSrc> &maskUbTensorSrc, | ||
| 456 | + uint32_t rowNumCurLoop, | ||
| 457 | + uint32_t columnNumRound) | ||
| 458 | + { | ||
| 459 | + AscendC::Cast<ElementMaskDst, ElementMaskSrc, false>( | ||
| 460 | + maskUbTensorDst, maskUbTensorSrc, AscendC::RoundMode::CAST_NONE, (uint64_t)0, | ||
| 461 | + CeilDiv(rowNumCurLoop * columnNumRound, (uint32_t)(REPEAT_SIZE_IN_BYTE / sizeof(ElementMaskDst))), | ||
| 462 | + AscendC::UnaryRepeatParams(1, 1, 8, 4)); | ||
| 463 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 464 | + } | ||
| 465 | + | ||
| 466 | + __aicore__ inline | ||
| 467 | + void ApplyMask(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t columnNumRound, uint32_t maskColumnRound, | ||
| 468 | + uint32_t addMaskUbOffset) | ||
| 469 | + { | ||
| 470 | + AscendC::Muls<half, false>( | ||
| 471 | + maskUbTensor16, | ||
| 472 | + maskUbTensor16, | ||
| 473 | + (half)-6e4, // -65504 | ||
| 474 | + (uint64_t)0, | ||
| 475 | + (rowNumCurLoop * maskColumnRound + HALF_VECTOR_SIZE - 1) / HALF_VECTOR_SIZE, | ||
| 476 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 477 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 478 | + if (maskColumnRound == columnNumRound) { | ||
| 479 | + AscendC::Add<half, false>( | ||
| 480 | + computeUbTensor, | ||
| 481 | + computeUbTensor, | ||
| 482 | + maskUbTensor16, | ||
| 483 | + (uint64_t)0, | ||
| 484 | + (rowNumCurLoop * maskColumnRound + HALF_VECTOR_SIZE - 1) / HALF_VECTOR_SIZE, | ||
| 485 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 486 | + } else { | ||
| 487 | + uint32_t loop = maskColumnRound / HALF_VECTOR_SIZE; | ||
| 488 | + for (uint32_t i = 0; i < loop; i++) { | ||
| 489 | + AscendC::Add<half, false>( | ||
| 490 | + computeUbTensor[addMaskUbOffset + i * HALF_VECTOR_SIZE], | ||
| 491 | + computeUbTensor[addMaskUbOffset + i * HALF_VECTOR_SIZE], | ||
| 492 | + maskUbTensor16[i * HALF_VECTOR_SIZE], | ||
| 493 | + (uint64_t)0, | ||
| 494 | + rowNumCurLoop, | ||
| 495 | + AscendC::BinaryRepeatParams(1, | ||
| 496 | + 1, | ||
| 497 | + 1, | ||
| 498 | + columnNumRound / BLOCK_SIZE, | ||
| 499 | + columnNumRound / BLOCK_SIZE, | ||
| 500 | + maskColumnRound / BLOCK_SIZE)); | ||
| 501 | + } | ||
| 502 | + if (maskColumnRound % HALF_VECTOR_SIZE > 0) { | ||
| 503 | + SetVecMask(maskColumnRound % HALF_VECTOR_SIZE); | ||
| 504 | + AscendC::Add<half, false>( | ||
| 505 | + computeUbTensor[addMaskUbOffset + loop * HALF_VECTOR_SIZE], | ||
| 506 | + computeUbTensor[addMaskUbOffset + loop * HALF_VECTOR_SIZE], | ||
| 507 | + maskUbTensor16[loop * HALF_VECTOR_SIZE], | ||
| 508 | + (uint64_t)0, | ||
| 509 | + rowNumCurLoop, | ||
| 510 | + AscendC::BinaryRepeatParams(1, | ||
| 511 | + 1, | ||
| 512 | + 1, | ||
| 513 | + columnNumRound / BLOCK_SIZE, | ||
| 514 | + columnNumRound / BLOCK_SIZE, | ||
| 515 | + maskColumnRound / BLOCK_SIZE)); | ||
| 516 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 517 | + } | ||
| 518 | + } | ||
| 519 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 520 | + } | ||
| 521 | + | ||
| 522 | + __aicore__ inline | ||
| 523 | + void CalcLocalRowMax(uint32_t sUbOffset, uint32_t rowNumCurLoopRound, uint32_t columnNum, uint32_t columnNumRound, | ||
| 524 | + uint32_t rowOffset) | ||
| 525 | + { | ||
| 526 | + if (columnNum == 1024U) { | ||
| 527 | + RowmaxSPECTILE1024( | ||
| 528 | + computeUbTensor, | ||
| 529 | + lmUbTensor[rowOffset], | ||
| 530 | + tvUbTensor, | ||
| 531 | + rowNumCurLoopRound, | ||
| 532 | + columnNum, | ||
| 533 | + columnNumRound); | ||
| 534 | + } else if (columnNum == 512U) { | ||
| 535 | + RowmaxSPECTILE512( | ||
| 536 | + computeUbTensor, | ||
| 537 | + lmUbTensor[rowOffset], | ||
| 538 | + tvUbTensor, | ||
| 539 | + rowNumCurLoopRound, | ||
| 540 | + columnNum, | ||
| 541 | + columnNumRound); | ||
| 542 | + } else { | ||
| 543 | + RowmaxTAILTILE( | ||
| 544 | + computeUbTensor, | ||
| 545 | + lmUbTensor[rowOffset], | ||
| 546 | + tvUbTensor, | ||
| 547 | + rowNumCurLoopRound, | ||
| 548 | + columnNum, | ||
| 549 | + columnNumRound); | ||
| 550 | + } | ||
| 551 | + } | ||
| 552 | + | ||
| 553 | + __aicore__ inline | ||
| 554 | + void UpdateGlobalRowMax(uint32_t rowNumCurLoop, uint32_t rowNumCurLoopRound, uint32_t columnNum, | ||
| 555 | + uint32_t columnNumRound, uint32_t dmUbOffsetCurCycle, uint32_t rowOffset, uint32_t isFirstStackTile) | ||
| 556 | + { | ||
| 557 | + if (isFirstStackTile) { | ||
| 558 | + AscendC::DataCopy( | ||
| 559 | + hmUbTensor[rowOffset], | ||
| 560 | + lmUbTensor[rowOffset], | ||
| 561 | + AscendC::DataCopyParams(1, rowNumCurLoopRound / BLOCK_SIZE, 0, 0)); | ||
| 562 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 563 | + } else { | ||
| 564 | + SetVecMask(rowNumCurLoop); | ||
| 565 | + // *** hm = vmax(lm, gm) | ||
| 566 | + AscendC::Max<half, false>( | ||
| 567 | + hmUbTensor[rowOffset], | ||
| 568 | + lmUbTensor[rowOffset], | ||
| 569 | + gmUbTensor[rowOffset], | ||
| 570 | + (uint64_t)0, | ||
| 571 | + 1, | ||
| 572 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 573 | + | ||
| 574 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 575 | + // *** dm = gm - hm | ||
| 576 | + AscendC::Sub<half, false>( | ||
| 577 | + dmUbTensor[dmUbOffsetCurCycle], | ||
| 578 | + gmUbTensor[rowOffset], | ||
| 579 | + hmUbTensor[rowOffset], | ||
| 580 | + (uint64_t)0, | ||
| 581 | + 1, | ||
| 582 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 583 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 584 | + // *** dm = exp(dm) | ||
| 585 | + AscendC::Exp<half, false>(dmUbTensor[dmUbOffsetCurCycle], | ||
| 586 | + dmUbTensor[dmUbOffsetCurCycle], | ||
| 587 | + (uint64_t)0, | ||
| 588 | + 1, | ||
| 589 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 590 | + } | ||
| 591 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 592 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 593 | + // *** gm = hm | ||
| 594 | + AscendC::DataCopy(gmUbTensor[rowOffset], | ||
| 595 | + hmUbTensor[rowOffset], | ||
| 596 | + AscendC::DataCopyParams(1, rowNumCurLoopRound / BLOCK_SIZE, 0, 0)); | ||
| 597 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 598 | + } | ||
| 599 | + | ||
| 600 | + __aicore__ inline | ||
| 601 | + void CalcExp(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t rowNumCurLoopRound, uint32_t columnNum, | ||
| 602 | + uint32_t columnNumRound, uint32_t rowOffset) | ||
| 603 | + { | ||
| 604 | + // *** hm_block = expand_to_block(hm), 存放于 tv | ||
| 605 | + AscendC::Brcb( | ||
| 606 | + tvUbTensor.template ReinterpretCast<uint16_t>(), | ||
| 607 | + hmUbTensor[rowOffset].template ReinterpretCast<uint16_t>(), | ||
| 608 | + rowNumCurLoopRound / FLOAT_BLOCK_SIZE, | ||
| 609 | + AscendC::BrcbRepeatParams(1, 8)); | ||
| 610 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 611 | + // *** ls = ls - hm_block | ||
| 612 | + for (uint32_t subIdx = 0; subIdx < columnNum / HALF_VECTOR_SIZE; ++subIdx) { | ||
| 613 | + AscendC::Sub<half, false>( | ||
| 614 | + computeUbTensor[subIdx * HALF_VECTOR_SIZE], | ||
| 615 | + computeUbTensor[subIdx * HALF_VECTOR_SIZE], | ||
| 616 | + tvUbTensor, | ||
| 617 | + (uint64_t)0, | ||
| 618 | + rowNumCurLoop, | ||
| 619 | + AscendC::BinaryRepeatParams( | ||
| 620 | + 1, 1, 0, columnNumRound / BLOCK_SIZE, columnNumRound / BLOCK_SIZE, 1)); | ||
| 621 | + } | ||
| 622 | + if (columnNum % HALF_VECTOR_SIZE > 0) { | ||
| 623 | + SetVecMask(columnNum % HALF_VECTOR_SIZE); | ||
| 624 | + AscendC::Sub<half, false>( | ||
| 625 | + computeUbTensor[columnNum / HALF_VECTOR_SIZE * HALF_VECTOR_SIZE], | ||
| 626 | + computeUbTensor[columnNum / HALF_VECTOR_SIZE * HALF_VECTOR_SIZE], | ||
| 627 | + tvUbTensor, | ||
| 628 | + (uint64_t)0, | ||
| 629 | + rowNumCurLoop, | ||
| 630 | + AscendC::BinaryRepeatParams( | ||
| 631 | + 1, 1, 0, columnNumRound / BLOCK_SIZE, columnNumRound / BLOCK_SIZE, 1)); | ||
| 632 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 633 | + } | ||
| 634 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 635 | + // *** ls = exp(ls) | ||
| 636 | + AscendC::Exp<half, false>( | ||
| 637 | + computeUbTensor, | ||
| 638 | + computeUbTensor, | ||
| 639 | + (uint64_t)0, | ||
| 640 | + (rowNumCurLoop * columnNumRound + HALF_VECTOR_SIZE - 1) / HALF_VECTOR_SIZE, | ||
| 641 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 642 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 643 | + } | ||
| 644 | + | ||
| 645 | + __aicore__ inline | ||
| 646 | + void CalcLocalRowSum(uint32_t sUbOffset, uint32_t rowNumCurLoopRound, uint32_t columnNum, uint32_t columnNumRound, | ||
| 647 | + uint32_t rowOffset) | ||
| 648 | + { | ||
| 649 | + // *** ll = rowsum(ls32) | ||
| 650 | + if (columnNum == 1024U) { | ||
| 651 | + RowsumSPECTILE1024( | ||
| 652 | + computeUbTensor, | ||
| 653 | + llUbTensor[rowOffset], | ||
| 654 | + tvUbTensor, | ||
| 655 | + rowNumCurLoopRound, | ||
| 656 | + columnNum, | ||
| 657 | + columnNumRound); | ||
| 658 | + } else if (columnNum == 512U) { | ||
| 659 | + RowsumSPECTILE512( | ||
| 660 | + computeUbTensor, | ||
| 661 | + llUbTensor[rowOffset], | ||
| 662 | + tvUbTensor, | ||
| 663 | + rowNumCurLoopRound, | ||
| 664 | + columnNum, | ||
| 665 | + columnNumRound); | ||
| 666 | + } else { | ||
| 667 | + RowsumTAILTILE( | ||
| 668 | + computeUbTensor, | ||
| 669 | + llUbTensor[rowOffset], | ||
| 670 | + tvUbTensor, | ||
| 671 | + rowNumCurLoopRound, | ||
| 672 | + columnNum, | ||
| 673 | + columnNumRound); | ||
| 674 | + } | ||
| 675 | + } | ||
| 676 | + | ||
| 677 | + __aicore__ inline | ||
| 678 | + void UpdateGlobalRowSum(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t rowNumCurLoopRound, | ||
| 679 | + uint32_t dmUbOffsetCurCycle, uint32_t rowOffset, uint32_t isFirstStackTile) | ||
| 680 | + { | ||
| 681 | + if (isFirstStackTile) { | ||
| 682 | + // *** gl = ll | ||
| 683 | + AscendC::DataCopy( | ||
| 684 | + glUbTensor[rowOffset], | ||
| 685 | + llUbTensor[rowOffset], | ||
| 686 | + AscendC::DataCopyParams(1, rowNumCurLoopRound / BLOCK_SIZE, 0, 0)); | ||
| 687 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 688 | + } else { | ||
| 689 | + SetVecMask(rowNumCurLoop); | ||
| 690 | + // *** gl = dm * gl | ||
| 691 | + AscendC::Mul<half, false>( | ||
| 692 | + glUbTensor[rowOffset], | ||
| 693 | + dmUbTensor[dmUbOffsetCurCycle], | ||
| 694 | + glUbTensor[rowOffset], | ||
| 695 | + (uint64_t)0, | ||
| 696 | + 1, | ||
| 697 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 698 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 699 | + // *** gl = ll + gl | ||
| 700 | + AscendC::Add<half, false>( | ||
| 701 | + glUbTensor[rowOffset], | ||
| 702 | + glUbTensor[rowOffset], | ||
| 703 | + llUbTensor[rowOffset], | ||
| 704 | + (uint64_t)0, | ||
| 705 | + 1, | ||
| 706 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 707 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 708 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 709 | + } | ||
| 710 | + } | ||
| 711 | + | ||
| 712 | + __aicore__ inline | ||
| 713 | + void MoveP(uint32_t sUbOffset, uint32_t rowNumCurLoop, uint32_t columnNumRound) | ||
| 714 | + { | ||
| 715 | + AscendC::DataCopyParams repeatParams; | ||
| 716 | + repeatParams.blockCount = 1; | ||
| 717 | + repeatParams.srcStride = 0; | ||
| 718 | + repeatParams.blockLen = CeilDiv(rowNumCurLoop * columnNumRound, BLOCK_SIZE); | ||
| 719 | + AscendC::DataCopy<half>(lpUbTensor[sUbOffset], computeUbTensor, repeatParams); | ||
| 720 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 721 | + } | ||
| 722 | + | ||
| 723 | + __aicore__ inline | ||
| 724 | + void CopyPUbToGm(AscendC::GlobalTensor<ElementOutput> gOutput, uint32_t sUbOffset, uint32_t rowNumCurLoop, | ||
| 725 | + uint32_t columnNumRound, uint32_t columnNumPad) | ||
| 726 | + { | ||
| 727 | + AscendC::DataCopy(gOutput, | ||
| 728 | + lpUbTensor[sUbOffset], | ||
| 729 | + AscendC::DataCopyParams( | ||
| 730 | + rowNumCurLoop, columnNumRound / BLOCK_SIZE, 0, (columnNumPad - columnNumRound) / BLOCK_SIZE)); | ||
| 731 | + } | ||
| 732 | + | ||
| 733 | + __aicore__ inline | ||
| 734 | + void SubCoreCompute( | ||
| 735 | + AscendC::GlobalTensor<ElementOutput> gOutput, const LayoutOutput &layoutOutput, | ||
| 736 | + uint32_t rowOffset, uint32_t isFirstStackTile, uint32_t isFirstRowLoop, | ||
| 737 | + uint32_t columnNumRound, uint32_t pingpongFlag, | ||
| 738 | + uint32_t curStackTileMod, Arch::CrossCoreFlag softmaxFlag, uint32_t isLastLoop) | ||
| 739 | + { | ||
| 740 | + uint32_t rowNumCurLoop = layoutOutput.shape(0); | ||
| 741 | + uint32_t rowNumCurLoopRound = RoundUp(rowNumCurLoop, BLOCK_SIZE); | ||
| 742 | + uint32_t columnNum = layoutOutput.shape(1); | ||
| 743 | + uint32_t columnNumPad = layoutOutput.stride(0); | ||
| 744 | + uint32_t sUbOffset = pingpongFlag * MAX_UB_S_ELEM_NUM; | ||
| 745 | + uint32_t dmUbOffsetCurCycle = curStackTileMod * MAX_ROW_NUM_SUB_CORE + rowOffset; | ||
| 746 | + | ||
| 747 | + if constexpr (LSE_MODE_ == LseMode::OUT_ONLY) { | ||
| 748 | + // wait for lse from ub to gm (low pre) | ||
| 749 | + // In lse out-only mode, tv is used in the last stack tile to transport lse | ||
| 750 | + if (isFirstStackTile && isFirstRowLoop) { | ||
| 751 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 752 | + } | ||
| 753 | + } | ||
| 754 | + CalcLocalRowMax(sUbOffset, rowNumCurLoopRound, columnNum, columnNumRound, rowOffset); | ||
| 755 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 756 | + UpdateGlobalRowMax(rowNumCurLoop, | ||
| 757 | + rowNumCurLoopRound, | ||
| 758 | + columnNum, | ||
| 759 | + columnNumRound, | ||
| 760 | + dmUbOffsetCurCycle, | ||
| 761 | + rowOffset, | ||
| 762 | + isFirstStackTile); | ||
| 763 | + CalcExp(sUbOffset, rowNumCurLoop, rowNumCurLoopRound, columnNum, columnNumRound, rowOffset); | ||
| 764 | + | ||
| 765 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(pingpongFlag); | ||
| 766 | + MoveP(sUbOffset, rowNumCurLoop, columnNumRound); | ||
| 767 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID0); | ||
| 768 | + | ||
| 769 | + CalcLocalRowSum(sUbOffset, rowNumCurLoopRound, columnNum, columnNumRound, rowOffset); | ||
| 770 | + | ||
| 771 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID0); | ||
| 772 | + CopyPUbToGm(gOutput, sUbOffset, rowNumCurLoop, columnNumRound, columnNumPad); | ||
| 773 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(pingpongFlag); | ||
| 774 | + if (isLastLoop) { | ||
| 775 | + NpuArch::Arch::CrossCoreSetFlag<0x2, PIPE_MTE3>(softmaxFlag); | ||
| 776 | + } | ||
| 777 | + UpdateGlobalRowSum( | ||
| 778 | + sUbOffset, rowNumCurLoop, rowNumCurLoopRound, dmUbOffsetCurCycle, rowOffset, isFirstStackTile); | ||
| 779 | + } | ||
| 780 | + | ||
| 781 | + __aicore__ inline | ||
| 782 | + void operator()(AscendC::GlobalTensor<ElementOutput> gOutput, AscendC::GlobalTensor<half> gInput, | ||
| 783 | + const LayoutOutput &layoutOutput, const LayoutInput &layoutInput, GemmCoord actualBlockShape, | ||
| 784 | + uint32_t isFirstStackTile, uint32_t isLastNoMaskStackTile, | ||
| 785 | + uint32_t qSBlockSize, uint32_t qNBlockSize, uint32_t curStackTileMod, Arch::CrossCoreFlag softmaxFlag) | ||
| 786 | + { | ||
| 787 | + uint32_t rowNum = actualBlockShape.m(); | ||
| 788 | + uint32_t columnNum = actualBlockShape.n(); | ||
| 789 | + uint32_t columnNumRound = RoundUp(columnNum, BLOCK_SIZE); | ||
| 790 | + uint32_t columnNumPad = layoutInput.stride(0); | ||
| 791 | + | ||
| 792 | + uint32_t subBlockIdx = AscendC::GetSubBlockIdx(); | ||
| 793 | + uint32_t subBlockNum = AscendC::GetSubBlockNum(); | ||
| 794 | + | ||
| 795 | + uint32_t qNSplitSubBlock = qNBlockSize / subBlockNum; | ||
| 796 | + uint32_t qNThisSubBlock = (qNBlockSize == 1U) ? | ||
| 797 | + 0 : (subBlockIdx == 1U) ? (qNBlockSize - qNSplitSubBlock) : qNSplitSubBlock; | ||
| 798 | + uint32_t rowSplitSubBlock = (qNBlockSize == 1U) ? (qSBlockSize / 2U) : (qSBlockSize * qNSplitSubBlock); | ||
| 799 | + uint32_t rowActualThisSubBlock = (subBlockIdx == 1U) ? (rowNum - rowSplitSubBlock) : rowSplitSubBlock; | ||
| 800 | + uint32_t rowOffsetThisSubBlock = subBlockIdx * rowSplitSubBlock; | ||
| 801 | + uint32_t maxRowNumPerLoop = MAX_UB_S_ELEM_NUM / columnNumRound; | ||
| 802 | + uint32_t rowNumTile = RoundDown(maxRowNumPerLoop, BLOCK_SIZE); | ||
| 803 | + rowNumTile = AscendC::Std::min(rowNumTile, HALF_VECTOR_SIZE); | ||
| 804 | + uint32_t rowLoopNum = CeilDiv(rowActualThisSubBlock, rowNumTile); | ||
| 805 | + | ||
| 806 | + if (rowActualThisSubBlock == 0) { | ||
| 807 | + NpuArch::Arch::CrossCoreSetFlag<0x2, PIPE_MTE3>(softmaxFlag); | ||
| 808 | + return; | ||
| 809 | + } | ||
| 810 | + | ||
| 811 | + for (uint32_t rowLoopIdx = 0; rowLoopIdx < rowLoopNum; rowLoopIdx++) { | ||
| 812 | + uint32_t pingpongFlag = rowLoopIdx % 2U; | ||
| 813 | + uint32_t rowOffsetCurLoop = rowLoopIdx * rowNumTile; | ||
| 814 | + uint32_t rowOffsetIoGm = rowOffsetCurLoop + rowOffsetThisSubBlock; | ||
| 815 | + uint32_t rowNumCurLoop = | ||
| 816 | + (rowLoopIdx == rowLoopNum - 1U) ? (rowActualThisSubBlock - rowOffsetCurLoop) : rowNumTile; | ||
| 817 | + | ||
| 818 | + int64_t offsetInput = layoutInput.GetOffset(MatrixCoord(rowOffsetIoGm, 0)); | ||
| 819 | + auto gInputCurLoop = gInput[offsetInput]; | ||
| 820 | + | ||
| 821 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 822 | + CopySGmToUb( | ||
| 823 | + gInputCurLoop, (pingpongFlag * MAX_UB_S_ELEM_NUM), rowNumCurLoop, columnNumRound, columnNumPad); | ||
| 824 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 825 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 826 | + ScaleS((pingpongFlag * MAX_UB_S_ELEM_NUM), rowNumCurLoop, columnNumRound); | ||
| 827 | + | ||
| 828 | + int64_t offsetOutput = layoutOutput.GetOffset(MatrixCoord(rowOffsetIoGm, 0)); | ||
| 829 | + auto gOutputCurLoop = gOutput[offsetOutput]; | ||
| 830 | + auto layoutOutputCurLoop = layoutOutput.GetTileLayout(MatrixCoord(rowNumCurLoop, columnNum)); | ||
| 831 | + SubCoreCompute( | ||
| 832 | + gOutputCurLoop, | ||
| 833 | + layoutOutputCurLoop, | ||
| 834 | + rowOffsetCurLoop, | ||
| 835 | + isFirstStackTile, | ||
| 836 | + (rowLoopIdx == 0U), | ||
| 837 | + columnNumRound, | ||
| 838 | + pingpongFlag, | ||
| 839 | + curStackTileMod, | ||
| 840 | + softmaxFlag, | ||
| 841 | + (rowLoopIdx == rowLoopNum - 1)); | ||
| 842 | + } | ||
| 843 | + } | ||
| 844 | + | ||
| 845 | + __aicore__ inline | ||
| 846 | + void operator()(AscendC::GlobalTensor<ElementOutput> gOutput, AscendC::GlobalTensor<half> gInput, | ||
| 847 | + AscendC::GlobalTensor<ElementMask> gMask, const LayoutOutput &layoutOutput, const LayoutInput &layoutInput, | ||
| 848 | + const LayoutInput &layoutMask, GemmCoord actualBlockShape, uint32_t isFirstStackTile, uint32_t qSBlockSize, | ||
| 849 | + uint32_t qNBlockSize, uint32_t curStackTileMod, Arch::CrossCoreFlag qkReady, uint32_t triUp, uint32_t triDown, | ||
| 850 | + uint32_t kvSStartIdx, uint32_t kvSEndIdx, Arch::CrossCoreFlag softmaxFlag) | ||
| 851 | + { | ||
| 852 | + uint32_t rowNum = actualBlockShape.m(); | ||
| 853 | + uint32_t columnNum = actualBlockShape.n(); | ||
| 854 | + uint32_t columnNumRound = RoundUp(columnNum, BLOCK_SIZE); | ||
| 855 | + uint32_t columnNumPad = layoutInput.stride(0); | ||
| 856 | + uint32_t maskStride = layoutMask.stride(0); | ||
| 857 | + uint32_t subBlockIdx = AscendC::GetSubBlockIdx(); | ||
| 858 | + uint32_t subBlockNum = AscendC::GetSubBlockNum(); | ||
| 859 | + | ||
| 860 | + uint32_t qNSplitSubBlock = qNBlockSize / subBlockNum; | ||
| 861 | + uint32_t qNThisSubBlock = (qNBlockSize == 1U) ? | ||
| 862 | + 0 : (subBlockIdx == 1U) ? (qNBlockSize - qNSplitSubBlock) : qNSplitSubBlock; | ||
| 863 | + uint32_t rowSplitSubBlock = (qNBlockSize == 1U) ? (qSBlockSize / 2U) : (qSBlockSize * qNSplitSubBlock); | ||
| 864 | + uint32_t rowActualThisSubBlock = (subBlockIdx == 1U) ? (rowNum - rowSplitSubBlock) : rowSplitSubBlock; | ||
| 865 | + uint32_t rowOffsetThisSubBlock = subBlockIdx * rowSplitSubBlock; | ||
| 866 | + | ||
| 867 | + uint32_t tokenNumPerHeadThisSubBlock = AscendC::Std::min(qSBlockSize, rowActualThisSubBlock); | ||
| 868 | + | ||
| 869 | + uint32_t maskOffsetThisSubBlock = (qNBlockSize == 1U) ? rowOffsetThisSubBlock : 0; | ||
| 870 | + | ||
| 871 | + uint32_t gmOffsetMaskRow; | ||
| 872 | + uint32_t gmOffsetMaskColumn; | ||
| 873 | + uint32_t maskColumn; | ||
| 874 | + uint32_t addMaskUbOffset; | ||
| 875 | + if (triUp >= kvSStartIdx) { | ||
| 876 | + uint32_t triUpRoundDown = RoundDown(triUp, BLOCK_SIZE); | ||
| 877 | + gmOffsetMaskRow = triUp - triUpRoundDown; | ||
| 878 | + gmOffsetMaskColumn = 0U; | ||
| 879 | + maskColumn = kvSEndIdx - triUpRoundDown; | ||
| 880 | + addMaskUbOffset = triUpRoundDown - kvSStartIdx; | ||
| 881 | + } else { | ||
| 882 | + gmOffsetMaskRow = 0U; | ||
| 883 | + gmOffsetMaskColumn = kvSStartIdx - triUp; | ||
| 884 | + maskColumn = columnNum; | ||
| 885 | + addMaskUbOffset = 0U; | ||
| 886 | + } | ||
| 887 | + uint32_t maskColumnRound = RoundUp(maskColumn, BLOCK_SIZE); | ||
| 888 | + | ||
| 889 | + int64_t offsetMask = | ||
| 890 | + layoutMask.GetOffset(MatrixCoord(gmOffsetMaskRow + maskOffsetThisSubBlock, gmOffsetMaskColumn)); | ||
| 891 | + auto gMaskThisSubBlock = gMask[offsetMask]; | ||
| 892 | + auto layoutMaskThisSubBlock = layoutMask; | ||
| 893 | + | ||
| 894 | + uint32_t maxRowNumPerLoop = MAX_UB_S_ELEM_NUM / columnNumRound; | ||
| 895 | + uint32_t rowNumTile = RoundDown(maxRowNumPerLoop, BLOCK_SIZE); | ||
| 896 | + rowNumTile = AscendC::Std::min(rowNumTile, HALF_VECTOR_SIZE); | ||
| 897 | + uint32_t rowLoopNum = CeilDiv(rowActualThisSubBlock, rowNumTile); | ||
| 898 | + | ||
| 899 | + if (rowActualThisSubBlock == 0U) { | ||
| 900 | + Arch::CrossCoreWaitFlag(qkReady); | ||
| 901 | + return; | ||
| 902 | + } | ||
| 903 | + Arch::CrossCoreWaitFlag(qkReady); | ||
| 904 | + for (uint32_t rowLoopIdx = 0; rowLoopIdx < rowLoopNum; rowLoopIdx++) { | ||
| 905 | + uint32_t pingpongFlag = rowLoopIdx % 2U; | ||
| 906 | + uint32_t rowOffsetCurLoop = rowLoopIdx * rowNumTile; | ||
| 907 | + uint32_t rowOffsetIoGm = rowOffsetCurLoop + rowOffsetThisSubBlock; | ||
| 908 | + uint32_t rowNumCurLoop = | ||
| 909 | + (rowLoopIdx == rowLoopNum - 1U) ? (rowActualThisSubBlock - rowOffsetCurLoop) : rowNumTile; | ||
| 910 | + | ||
| 911 | + uint32_t proTokenIdx = rowOffsetCurLoop % tokenNumPerHeadThisSubBlock; | ||
| 912 | + uint32_t proTokenNum = AscendC::Std::min(rowNumCurLoop, (tokenNumPerHeadThisSubBlock - proTokenIdx)) % | ||
| 913 | + tokenNumPerHeadThisSubBlock; | ||
| 914 | + uint32_t integralHeadNum = (rowNumCurLoop - proTokenNum) / tokenNumPerHeadThisSubBlock; | ||
| 915 | + uint32_t epiTokenNum = rowNumCurLoop - proTokenNum - integralHeadNum * tokenNumPerHeadThisSubBlock; | ||
| 916 | + | ||
| 917 | + int64_t offsetInput = layoutInput.GetOffset(MatrixCoord(rowOffsetIoGm, 0)); | ||
| 918 | + auto gInputCurLoop = gInput[offsetInput]; | ||
| 919 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 920 | + CopySGmToUb( | ||
| 921 | + gInputCurLoop, (pingpongFlag * MAX_UB_S_ELEM_NUM), rowNumCurLoop, columnNumRound, columnNumPad); | ||
| 922 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 923 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 924 | + ScaleS((pingpongFlag * MAX_UB_S_ELEM_NUM), rowNumCurLoop, columnNumRound); | ||
| 925 | + | ||
| 926 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID3); | ||
| 927 | + CopyMaskGmToUb( | ||
| 928 | + gMaskThisSubBlock, | ||
| 929 | + maskColumn, | ||
| 930 | + maskColumnRound, | ||
| 931 | + maskStride, | ||
| 932 | + tokenNumPerHeadThisSubBlock, | ||
| 933 | + proTokenIdx, | ||
| 934 | + proTokenNum, | ||
| 935 | + integralHeadNum, | ||
| 936 | + epiTokenNum); | ||
| 937 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID1); | ||
| 938 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID1); | ||
| 939 | + UpCastMask<half, ElementMask>(maskUbTensor16, maskUbTensor, rowNumCurLoop, columnNumRound); | ||
| 940 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID3); | ||
| 941 | + ApplyMask( | ||
| 942 | + (pingpongFlag * MAX_UB_S_ELEM_NUM), | ||
| 943 | + rowNumCurLoop, | ||
| 944 | + columnNumRound, | ||
| 945 | + maskColumnRound, | ||
| 946 | + addMaskUbOffset); | ||
| 947 | + | ||
| 948 | + // online softmax vectorized compute | ||
| 949 | + int64_t offsetOutput = layoutOutput.GetOffset(MatrixCoord(rowOffsetIoGm, 0)); | ||
| 950 | + auto gOutputCurLoop = gOutput[offsetOutput]; | ||
| 951 | + auto layoutOutputCurLoop = layoutOutput.GetTileLayout(MatrixCoord(rowNumCurLoop, columnNum)); | ||
| 952 | + SubCoreCompute( | ||
| 953 | + gOutputCurLoop, | ||
| 954 | + layoutOutputCurLoop, | ||
| 955 | + rowOffsetCurLoop, | ||
| 956 | + isFirstStackTile, | ||
| 957 | + (rowLoopIdx == 0), | ||
| 958 | + columnNumRound, | ||
| 959 | + pingpongFlag, | ||
| 960 | + curStackTileMod, | ||
| 961 | + softmaxFlag, | ||
| 962 | + 0); | ||
| 963 | + } | ||
| 964 | + } | ||
| 965 | + | ||
| 966 | +private: | ||
| 967 | + half scaleValue; | ||
| 968 | + AscendC::LocalTensor<half> lsUbTensor; | ||
| 969 | + AscendC::LocalTensor<half> computeUbTensor; | ||
| 970 | + AscendC::LocalTensor<ElementOutput> lpUbTensor; | ||
| 971 | + AscendC::LocalTensor<ElementMask> maskUbTensor; | ||
| 972 | + AscendC::LocalTensor<half> maskUbTensor16; | ||
| 973 | + AscendC::LocalTensor<half> lmUbTensor; | ||
| 974 | + AscendC::LocalTensor<half> hmUbTensor; | ||
| 975 | + AscendC::LocalTensor<half> gmUbTensor; | ||
| 976 | + AscendC::LocalTensor<half> dmUbTensor; | ||
| 977 | + AscendC::LocalTensor<half> llUbTensor; | ||
| 978 | + AscendC::LocalTensor<half> tvUbTensor; | ||
| 979 | + AscendC::LocalTensor<half> glUbTensor; | ||
| 980 | +}; | ||
| 981 | +} | ||
| 982 | + | ||
| 983 | + | ||
| @@ -0,0 +1,461 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace NpuArch::Epilogue::Block { | ||
| 22 | + | ||
| 23 | +template < | ||
| 24 | + class OutputType_, | ||
| 25 | + class InputType_, | ||
| 26 | + class UpdateType_, | ||
| 27 | + class LseType_, | ||
| 28 | + LseMode LSE_MODE_> | ||
| 29 | +class BlockEpilogue< | ||
| 30 | + EpilogueAtlasA2RescaleO<LSE_MODE_, float>, | ||
| 31 | + OutputType_, | ||
| 32 | + InputType_, | ||
| 33 | + UpdateType_, | ||
| 34 | + LseType_> | ||
| 35 | +{ | ||
| 36 | +public: | ||
| 37 | + // Type aliases | ||
| 38 | + using DispatchPolicy = EpilogueAtlasA2RescaleO<LSE_MODE_, float>; | ||
| 39 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 40 | + | ||
| 41 | + using ElementOutput = typename OutputType_::Element; | ||
| 42 | + using ElementInput = typename InputType_::Element; | ||
| 43 | + using ElementUpdate = typename UpdateType_::Element; | ||
| 44 | + using ElementLse = typename LseType_::Element; | ||
| 45 | + | ||
| 46 | + using LayoutOutput = typename OutputType_::Layout; | ||
| 47 | + using LayoutInput = typename InputType_::Layout; | ||
| 48 | + using LayoutUpdate = typename UpdateType_::Layout; | ||
| 49 | + using LayoutLse = typename LseType_::Layout; | ||
| 50 | + | ||
| 51 | + static constexpr LseMode LSE_MODE = DispatchPolicy::LSE_MODE; | ||
| 52 | + | ||
| 53 | + static constexpr uint32_t HALF_ELENUM_PER_BLK = 16; | ||
| 54 | + static constexpr uint32_t BLOCK_SIZE = 16; | ||
| 55 | + static constexpr uint32_t HALF_ELENUM_PER_VECCALC = 128; | ||
| 56 | + static constexpr uint32_t FLOAT_ELENUM_PER_VECCALC = 64; | ||
| 57 | + static constexpr uint32_t HALF_ELENUM_PER_LINE = 256; | ||
| 58 | + static constexpr uint32_t FLOAT_ELENUM_PER_LINE = 128; | ||
| 59 | + static constexpr uint32_t MULTIPLIER = 2; | ||
| 60 | + static constexpr uint32_t FLOAT_BLOCK_SIZE = 8; | ||
| 61 | + static constexpr uint32_t FLOAT_VECTOR_SIZE = 64; | ||
| 62 | + static constexpr uint32_t UB_UINT8_VECTOR_SIZE = 1024; | ||
| 63 | + static constexpr uint32_t UB_UINT8_BLOCK_SIZE = 16384; | ||
| 64 | + static constexpr uint32_t HALF_DM_UB_SIZE = 64; | ||
| 65 | + static constexpr uint32_t HALF_LL_UB_SIZE = 256; | ||
| 66 | + static constexpr uint32_t VECTOR_SIZE = 128; | ||
| 67 | + static constexpr uint32_t NUM4 = 4; | ||
| 68 | + static constexpr uint32_t MAX_UB_O_ELEM_NUM = 8192; | ||
| 69 | + static constexpr uint32_t MAX_ROW_NUM_SUB_CORE = 256; | ||
| 70 | + static constexpr uint32_t SIZE_OF_16BIT = 2; | ||
| 71 | + | ||
| 72 | + __aicore__ inline | ||
| 73 | + BlockEpilogue(Arch::Resource<ArchTag> &resource) | ||
| 74 | + { | ||
| 75 | + // Allocate UB space | ||
| 76 | + constexpr uint32_t LO_UB_TENSOR_OFFSET = 6 * UB_UINT8_BLOCK_SIZE; | ||
| 77 | + constexpr uint32_t GO_UB_TENSOR_OFFSET = 8 * UB_UINT8_BLOCK_SIZE; | ||
| 78 | + constexpr uint32_t TV_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE; | ||
| 79 | + | ||
| 80 | + constexpr uint32_t HM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 9 * UB_UINT8_VECTOR_SIZE; | ||
| 81 | + constexpr uint32_t GM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 10 * UB_UINT8_VECTOR_SIZE; | ||
| 82 | + constexpr uint32_t GL_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 12 * UB_UINT8_VECTOR_SIZE; | ||
| 83 | + constexpr uint32_t LSE_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 12 * UB_UINT8_VECTOR_SIZE; | ||
| 84 | + constexpr uint32_t DM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 13 * UB_UINT8_VECTOR_SIZE; | ||
| 85 | + | ||
| 86 | + loUbTensor = resource.ubBuf.template GetBufferByByte<float>(LO_UB_TENSOR_OFFSET); | ||
| 87 | + dmUbTensor = resource.ubBuf.template GetBufferByByte<float>(DM_UB_TENSOR_OFFSET); | ||
| 88 | + glUbTensor = resource.ubBuf.template GetBufferByByte<float>(GL_UB_TENSOR_OFFSET); | ||
| 89 | + tvUbTensor = resource.ubBuf.template GetBufferByByte<float>(TV_UB_TENSOR_OFFSET); | ||
| 90 | + goUbTensor16 = resource.ubBuf.template GetBufferByByte<ElementOutput>(GO_UB_TENSOR_OFFSET); | ||
| 91 | + goUbTensor32 = resource.ubBuf.template GetBufferByByte<float>(GO_UB_TENSOR_OFFSET); | ||
| 92 | + hmUbTensor = resource.ubBuf.template GetBufferByByte<float>(HM_UB_TENSOR_OFFSET); | ||
| 93 | + gmUbTensor = resource.ubBuf.template GetBufferByByte<float>(GM_UB_TENSOR_OFFSET); | ||
| 94 | + lse32_ubuf_tensor = resource.ubBuf.template GetBufferByByte<float>(LSE_UB_TENSOR_OFFSET); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + __aicore__ inline | ||
| 98 | + ~BlockEpilogue() {} | ||
| 99 | + | ||
| 100 | + __aicore__ inline | ||
| 101 | + void SetMask(int32_t len) | ||
| 102 | + { | ||
| 103 | + uint64_t mask = 0; | ||
| 104 | + uint64_t one = 1; | ||
| 105 | + uint64_t temp = static_cast<uint64_t>(len) % static_cast<uint64_t>(FLOAT_VECTOR_SIZE); | ||
| 106 | + for (uint64_t i = 0; i < temp; i++) { | ||
| 107 | + mask |= one << i; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + if (len == VECTOR_SIZE) { | ||
| 111 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 112 | + } else if (len >= FLOAT_VECTOR_SIZE) { | ||
| 113 | + AscendC::SetVectorMask<int8_t>(mask, (uint64_t)-1); | ||
| 114 | + } else { | ||
| 115 | + AscendC::SetVectorMask<int8_t>(0x0, mask); | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + __aicore__ inline | ||
| 120 | + void CopyOToGm(AscendC::GlobalTensor<ElementOutput> gOutput, uint32_t proTokenIdx, uint32_t proTokenNum, | ||
| 121 | + uint32_t epiTokenNum, uint32_t integralHeadNum, uint32_t qSThisSubBlock, uint32_t embed, uint32_t oHiddenSize) | ||
| 122 | + { | ||
| 123 | + uint32_t innerOGmOffset = 0; | ||
| 124 | + uint32_t innerGOUbOffset = 0; | ||
| 125 | + if (proTokenNum != 0U) { | ||
| 126 | + AscendC::DataCopyPad( | ||
| 127 | + gOutput[innerOGmOffset + proTokenIdx * oHiddenSize], | ||
| 128 | + goUbTensor16[innerGOUbOffset], | ||
| 129 | + AscendC::DataCopyExtParams( | ||
| 130 | + proTokenNum, embed * SIZE_OF_16BIT, 0, (oHiddenSize - embed) * SIZE_OF_16BIT, 0)); | ||
| 131 | + innerOGmOffset += embed; | ||
| 132 | + innerGOUbOffset += proTokenNum * embed; | ||
| 133 | + } | ||
| 134 | + for (uint32_t qN_idx = 0; qN_idx < integralHeadNum; qN_idx++) { | ||
| 135 | + AscendC::DataCopyPad( | ||
| 136 | + gOutput[innerOGmOffset], | ||
| 137 | + goUbTensor16[innerGOUbOffset], | ||
| 138 | + AscendC::DataCopyExtParams( | ||
| 139 | + qSThisSubBlock, embed * SIZE_OF_16BIT, 0, (oHiddenSize - embed) * SIZE_OF_16BIT, 0)); | ||
| 140 | + innerOGmOffset += embed; | ||
| 141 | + innerGOUbOffset += qSThisSubBlock * embed; | ||
| 142 | + } | ||
| 143 | + if (epiTokenNum != 0U) { | ||
| 144 | + AscendC::DataCopyPad( | ||
| 145 | + gOutput[innerOGmOffset], | ||
| 146 | + goUbTensor16[innerGOUbOffset], | ||
| 147 | + AscendC::DataCopyExtParams( | ||
| 148 | + epiTokenNum, embed * SIZE_OF_16BIT, 0, (oHiddenSize - embed) * SIZE_OF_16BIT, 0)); | ||
| 149 | + } | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + __aicore__ inline | ||
| 153 | + void SubCoreCompute( | ||
| 154 | + AscendC::GlobalTensor<ElementOutput> gOutput, | ||
| 155 | + AscendC::GlobalTensor<ElementInput> gInput, | ||
| 156 | + AscendC::GlobalTensor<ElementUpdate> gUpdate, | ||
| 157 | + AscendC::GlobalTensor<ElementLse> gLse, | ||
| 158 | + const LayoutOutput &layoutOutput, | ||
| 159 | + const LayoutInput &layoutInput, | ||
| 160 | + const LayoutUpdate &layoutUpdate, | ||
| 161 | + const LayoutLse &layoutLse, | ||
| 162 | + uint32_t qNThisSubBlock, uint32_t qSThisSubBlock, uint32_t totalRowNum, | ||
| 163 | + uint32_t isFirstStackTile, uint32_t isLastStackTile, uint32_t curStackTileMod, | ||
| 164 | + uint32_t needRowLoop, uint32_t isLastRowLoop, uint32_t rowOffsetLoop, | ||
| 165 | + uint32_t proTokenIdx, uint32_t proTokenNum, uint32_t epiTokenNum, uint32_t integralHeadNum) | ||
| 166 | + { | ||
| 167 | + uint32_t curRowNum = layoutInput.shape(0); | ||
| 168 | + uint32_t embed = layoutInput.shape(1); | ||
| 169 | + uint32_t embedRound = layoutInput.stride(0); | ||
| 170 | + uint32_t curRowNumRound = RoundUp(curRowNum, FLOAT_BLOCK_SIZE); | ||
| 171 | + uint32_t qSBlockSize = layoutOutput.shape(0); | ||
| 172 | + uint32_t oHiddenSize = layoutOutput.shape(1); | ||
| 173 | + uint32_t stride = layoutLse.shape(1); // stride for lse copy out | ||
| 174 | + uint32_t dmUbOffsetCurStackTile = curStackTileMod * MAX_ROW_NUM_SUB_CORE + rowOffsetLoop; | ||
| 175 | + | ||
| 176 | + if (!isFirstStackTile) { | ||
| 177 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID3); | ||
| 178 | + AscendC::DataCopy( | ||
| 179 | + loUbTensor, gInput, AscendC::DataCopyParams(1, curRowNum * embedRound / FLOAT_BLOCK_SIZE, 0, 0)); | ||
| 180 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 181 | + } | ||
| 182 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID6); | ||
| 183 | + if (!isFirstStackTile) { | ||
| 184 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 185 | + AscendC::Brcb(tvUbTensor.ReinterpretCast<uint32_t>(), | ||
| 186 | + dmUbTensor[dmUbOffsetCurStackTile].ReinterpretCast<uint32_t>(), | ||
| 187 | + curRowNumRound / FLOAT_BLOCK_SIZE, | ||
| 188 | + AscendC::BrcbRepeatParams(1, 8)); | ||
| 189 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 190 | + if (needRowLoop) { | ||
| 191 | + AscendC::DataCopy( | ||
| 192 | + goUbTensor32, gUpdate, | ||
| 193 | + AscendC::DataCopyParams(1, curRowNum * embedRound / FLOAT_BLOCK_SIZE, 0, 0)); | ||
| 194 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID1); | ||
| 195 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID1); | ||
| 196 | + } | ||
| 197 | + // *** go = go * dm_block | ||
| 198 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 199 | + for (uint32_t vmul_idx = 0; vmul_idx < embed / FLOAT_VECTOR_SIZE; ++vmul_idx) { | ||
| 200 | + AscendC::Mul<float, false>( | ||
| 201 | + goUbTensor32[vmul_idx * FLOAT_VECTOR_SIZE], | ||
| 202 | + goUbTensor32[vmul_idx * FLOAT_VECTOR_SIZE], | ||
| 203 | + tvUbTensor, | ||
| 204 | + (uint64_t)0, | ||
| 205 | + curRowNum, | ||
| 206 | + AscendC::BinaryRepeatParams( | ||
| 207 | + 1, 1, 0, embedRound / FLOAT_BLOCK_SIZE, embedRound / FLOAT_BLOCK_SIZE, 1)); | ||
| 208 | + } | ||
| 209 | + if (embed % FLOAT_VECTOR_SIZE > 0) { | ||
| 210 | + SetMask(embed % FLOAT_VECTOR_SIZE); | ||
| 211 | + AscendC::Mul<float, false>( | ||
| 212 | + goUbTensor32[embed / FLOAT_VECTOR_SIZE * FLOAT_VECTOR_SIZE], | ||
| 213 | + goUbTensor32[embed / FLOAT_VECTOR_SIZE * FLOAT_VECTOR_SIZE], | ||
| 214 | + tvUbTensor, | ||
| 215 | + (uint64_t)0, | ||
| 216 | + curRowNum, | ||
| 217 | + AscendC::BinaryRepeatParams( | ||
| 218 | + 1, 1, 0, embedRound / FLOAT_BLOCK_SIZE, embedRound / FLOAT_BLOCK_SIZE, 1)); | ||
| 219 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 220 | + } | ||
| 221 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 222 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 223 | + // *** go = lo + go | ||
| 224 | + AscendC::Add<float, false>( | ||
| 225 | + goUbTensor32, | ||
| 226 | + goUbTensor32, | ||
| 227 | + loUbTensor, | ||
| 228 | + (uint64_t)0, | ||
| 229 | + (curRowNum * embedRound + FLOAT_VECTOR_SIZE - 1) / FLOAT_VECTOR_SIZE, | ||
| 230 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 231 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 232 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID3); | ||
| 233 | + } else { | ||
| 234 | + // *** go = lo | ||
| 235 | + AscendC::DataCopy( | ||
| 236 | + goUbTensor32, gInput, AscendC::DataCopyParams(1, curRowNum * embedRound / FLOAT_BLOCK_SIZE, 0, 0)); | ||
| 237 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 238 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + if (isLastStackTile) { | ||
| 242 | + // *** gl_block = expand_to_block(gl), 存放于 tv | ||
| 243 | + AscendC::Brcb( | ||
| 244 | + tvUbTensor.ReinterpretCast<uint32_t>(), | ||
| 245 | + glUbTensor.ReinterpretCast<uint32_t>()[rowOffsetLoop], | ||
| 246 | + curRowNumRound / FLOAT_BLOCK_SIZE, | ||
| 247 | + AscendC::BrcbRepeatParams(1, 8)); | ||
| 248 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 249 | + // *** go = go / gl_block | ||
| 250 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 251 | + for (uint32_t vdiv_idx = 0; vdiv_idx < embed / FLOAT_VECTOR_SIZE; ++vdiv_idx) { | ||
| 252 | + AscendC::Div<float, false>( | ||
| 253 | + goUbTensor32[vdiv_idx * FLOAT_VECTOR_SIZE], | ||
| 254 | + goUbTensor32[vdiv_idx * FLOAT_VECTOR_SIZE], | ||
| 255 | + tvUbTensor, | ||
| 256 | + (uint64_t)0, | ||
| 257 | + curRowNum, | ||
| 258 | + AscendC::BinaryRepeatParams( | ||
| 259 | + 1, 1, 0, embedRound / FLOAT_BLOCK_SIZE, embedRound / FLOAT_BLOCK_SIZE, 1)); | ||
| 260 | + } | ||
| 261 | + if (embed % FLOAT_VECTOR_SIZE > 0) { | ||
| 262 | + SetMask(embed % FLOAT_VECTOR_SIZE); | ||
| 263 | + AscendC::Div<float, false>( | ||
| 264 | + goUbTensor32[embed / FLOAT_VECTOR_SIZE * FLOAT_VECTOR_SIZE], | ||
| 265 | + goUbTensor32[embed / FLOAT_VECTOR_SIZE * FLOAT_VECTOR_SIZE], | ||
| 266 | + tvUbTensor, | ||
| 267 | + (uint64_t)0, | ||
| 268 | + curRowNum, | ||
| 269 | + AscendC::BinaryRepeatParams( | ||
| 270 | + 1, 1, 0, embedRound / FLOAT_BLOCK_SIZE, embedRound / FLOAT_BLOCK_SIZE, 1)); | ||
| 271 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 272 | + } | ||
| 273 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 274 | + | ||
| 275 | + // *** go = castfp32to16(go) | ||
| 276 | + if (std::is_same<ElementOutput, bfloat16_t>::value) { | ||
| 277 | + AscendC::Cast<ElementOutput, float, false>( | ||
| 278 | + goUbTensor16, goUbTensor32, | ||
| 279 | + AscendC::RoundMode::CAST_RINT, (uint64_t)0, | ||
| 280 | + (curRowNum * embedRound + FLOAT_VECTOR_SIZE - 1) / FLOAT_VECTOR_SIZE, | ||
| 281 | + AscendC::UnaryRepeatParams(1, 1, 4, 8)); | ||
| 282 | + } else { | ||
| 283 | + AscendC::Cast<ElementOutput, float, false>( | ||
| 284 | + goUbTensor16, goUbTensor32, | ||
| 285 | + AscendC::RoundMode::CAST_NONE, (uint64_t)0, | ||
| 286 | + (curRowNum * embedRound + FLOAT_VECTOR_SIZE - 1) / FLOAT_VECTOR_SIZE, | ||
| 287 | + AscendC::UnaryRepeatParams(1, 1, 4, 8)); | ||
| 288 | + } | ||
| 289 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID0); | ||
| 290 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID0); | ||
| 291 | + | ||
| 292 | + // ***move O to GM | ||
| 293 | + CopyOToGm( | ||
| 294 | + gOutput, proTokenIdx, proTokenNum, epiTokenNum, integralHeadNum, qSThisSubBlock, embed, oHiddenSize); | ||
| 295 | + if constexpr(LSE_MODE == LseMode::OUT_ONLY) { | ||
| 296 | + if (isLastRowLoop) { | ||
| 297 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 298 | + AscendC::Ln<float, false>( | ||
| 299 | + lse32_ubuf_tensor, | ||
| 300 | + glUbTensor, | ||
| 301 | + (uint64_t)0, | ||
| 302 | + CeilDiv(totalRowNum, FLOAT_VECTOR_SIZE), | ||
| 303 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 304 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 305 | + AscendC::Add<float, false>( | ||
| 306 | + lse32_ubuf_tensor, | ||
| 307 | + lse32_ubuf_tensor, | ||
| 308 | + gmUbTensor, | ||
| 309 | + (uint64_t)0, | ||
| 310 | + CeilDiv(totalRowNum, FLOAT_VECTOR_SIZE), | ||
| 311 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 312 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 313 | + AscendC::Brcb( | ||
| 314 | + tvUbTensor.ReinterpretCast<uint32_t>(), | ||
| 315 | + lse32_ubuf_tensor.ReinterpretCast<uint32_t>(), | ||
| 316 | + CeilDiv(totalRowNum, FLOAT_BLOCK_SIZE), | ||
| 317 | + AscendC::BrcbRepeatParams(1, 8)); | ||
| 318 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 319 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID4); | ||
| 320 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID4); | ||
| 321 | + if (qNThisSubBlock == 0U) { | ||
| 322 | + AscendC::DataCopyPad( | ||
| 323 | + gLse, tvUbTensor, | ||
| 324 | + AscendC::DataCopyExtParams(totalRowNum, sizeof(float), 0, (stride - 1) * sizeof(float), 0)); | ||
| 325 | + } else { | ||
| 326 | + for (uint32_t qNIdx = 0; qNIdx < qNThisSubBlock; qNIdx++) { | ||
| 327 | + AscendC::DataCopyPad( | ||
| 328 | + gLse[qNIdx], | ||
| 329 | + tvUbTensor[qNIdx * qSBlockSize * FLOAT_BLOCK_SIZE], | ||
| 330 | + AscendC::DataCopyExtParams( | ||
| 331 | + qSBlockSize, sizeof(float), 0, (stride - 1) * sizeof(float), 0)); | ||
| 332 | + } | ||
| 333 | + } | ||
| 334 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 335 | + } | ||
| 336 | + } | ||
| 337 | + } else if (needRowLoop) { | ||
| 338 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID5); | ||
| 339 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID5); | ||
| 340 | + AscendC::DataCopy( | ||
| 341 | + gUpdate, goUbTensor32, AscendC::DataCopyParams(1, curRowNum * embedRound / FLOAT_BLOCK_SIZE, 0, 0)); | ||
| 342 | + } | ||
| 343 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID6); | ||
| 344 | + } | ||
| 345 | + | ||
| 346 | + __aicore__ inline | ||
| 347 | + void operator()( | ||
| 348 | + AscendC::GlobalTensor<ElementOutput> gOutput, | ||
| 349 | + AscendC::GlobalTensor<ElementInput> gInput, | ||
| 350 | + AscendC::GlobalTensor<ElementUpdate> gUpdate, | ||
| 351 | + AscendC::GlobalTensor<ElementLse> gLse, | ||
| 352 | + const LayoutOutput &layoutOutput, | ||
| 353 | + const LayoutInput &layoutInput, | ||
| 354 | + const LayoutUpdate &layoutUpdate, | ||
| 355 | + const LayoutLse &layoutLse, | ||
| 356 | + GemmCoord actualBlockShape, | ||
| 357 | + uint32_t qSBlockSize, uint32_t qNBlockSize, | ||
| 358 | + uint32_t isFirstStackTile, uint32_t isLastStackTile, uint32_t curStackTileMod) | ||
| 359 | + { | ||
| 360 | + uint32_t rowNum = actualBlockShape.m(); | ||
| 361 | + uint32_t embed = actualBlockShape.n(); | ||
| 362 | + uint32_t maxRowNumPerLoop = MAX_UB_O_ELEM_NUM / embed; | ||
| 363 | + uint32_t rowNumTile = RoundDown(maxRowNumPerLoop, FLOAT_BLOCK_SIZE); | ||
| 364 | + | ||
| 365 | + uint32_t subBlockIdx = AscendC::GetSubBlockIdx(); | ||
| 366 | + uint32_t subBlockNum = AscendC::GetSubBlockNum(); | ||
| 367 | + | ||
| 368 | + uint32_t qNSplitSubBlock = qNBlockSize / subBlockNum; | ||
| 369 | + uint32_t qNThisSubBlock = (qNBlockSize == 1U) ? 0 | ||
| 370 | + : (subBlockIdx == 1U) ? (qNBlockSize - qNSplitSubBlock) | ||
| 371 | + : qNSplitSubBlock; | ||
| 372 | + uint32_t inRowSplitSubBlock = | ||
| 373 | + (qNBlockSize == 1U) ? (qSBlockSize / subBlockNum) : (qSBlockSize * qNSplitSubBlock); | ||
| 374 | + uint32_t inRowActualThisSubBlock = (subBlockIdx == 1U) ? (rowNum - inRowSplitSubBlock) : inRowSplitSubBlock; | ||
| 375 | + uint32_t inRowOffsetThisSubBlock = subBlockIdx * inRowSplitSubBlock; | ||
| 376 | + uint32_t outRowOffsetThisSubBlock = (qNBlockSize == 1U) ? inRowOffsetThisSubBlock : 0; | ||
| 377 | + uint32_t outColOffsetThisSubBlock = (qNBlockSize == 1U) ? 0 : subBlockIdx * qNSplitSubBlock * embed; | ||
| 378 | + uint32_t qSThisSubBlock = (qNBlockSize == 1U) ? inRowActualThisSubBlock : qSBlockSize; | ||
| 379 | + int64_t outOffsetSubBlock = | ||
| 380 | + layoutOutput.GetOffset(MatrixCoord(outRowOffsetThisSubBlock, outColOffsetThisSubBlock)); | ||
| 381 | + | ||
| 382 | + uint32_t outLseRowOffsetThisSubBlock = (qNBlockSize == 1U) ? inRowOffsetThisSubBlock : 0; | ||
| 383 | + uint32_t outLseColOffsetThisSubBlock = (qNBlockSize == 1U) ? 0 : subBlockIdx * qNSplitSubBlock; | ||
| 384 | + int64_t offsetLse = layoutLse.GetOffset(MatrixCoord(outLseRowOffsetThisSubBlock, outLseColOffsetThisSubBlock)); | ||
| 385 | + auto gLseThisSubBlock = gLse[offsetLse]; | ||
| 386 | + | ||
| 387 | + if (inRowActualThisSubBlock > 0U) { | ||
| 388 | + uint32_t rowLoop = CeilDiv(inRowActualThisSubBlock, rowNumTile); | ||
| 389 | + uint32_t needRowLoop = (rowLoop > 1U) ? 1 : 0; | ||
| 390 | + | ||
| 391 | + // The rows of each cycle consist of multiple heads with several tokens. | ||
| 392 | + // There are several integral heads, one prologue head, one epilogue head. | ||
| 393 | + uint32_t proTokenIdx = 0; // the token idx of the start token of the prologue part | ||
| 394 | + uint32_t proTokenIdxPre = 0; // the token idx of the start token of the pre prologue part | ||
| 395 | + uint32_t proTokenNum = 0; // the token num of the prologue part | ||
| 396 | + uint32_t epiTokenNum = 0; // the token num of the epilogue part | ||
| 397 | + uint32_t integralHeadNum = 0; // the number of integral heads within a cycle | ||
| 398 | + uint32_t qSRemian = qSThisSubBlock; | ||
| 399 | + for (uint32_t rowLoopIdx = 0; rowLoopIdx < rowLoop; rowLoopIdx++) { | ||
| 400 | + uint32_t rowOffsetLoop = rowLoopIdx * rowNumTile; | ||
| 401 | + uint32_t rowOffsetCurLoop = inRowOffsetThisSubBlock + rowOffsetLoop; | ||
| 402 | + uint32_t rowActualCurLoop = | ||
| 403 | + (rowLoopIdx == (rowLoop - 1U)) ? inRowActualThisSubBlock - rowLoopIdx * rowNumTile : rowNumTile; | ||
| 404 | + | ||
| 405 | + int64_t offsetOutput = | ||
| 406 | + static_cast<int64_t>(rowLoopIdx * rowNumTile / qSThisSubBlock * embed) + outOffsetSubBlock; | ||
| 407 | + auto gOutputCurLoop = gOutput[offsetOutput]; | ||
| 408 | + auto layoutOutputCurLoop = layoutOutput; | ||
| 409 | + int64_t offsetInput = layoutInput.GetOffset(MatrixCoord(rowOffsetCurLoop, 0)); | ||
| 410 | + auto gInputCurLoop = gInput[offsetInput]; | ||
| 411 | + auto layoutInputCurLoop = layoutInput.GetTileLayout(MatrixCoord(rowActualCurLoop, embed)); | ||
| 412 | + | ||
| 413 | + int64_t offsetUpdate = layoutUpdate.GetOffset(MatrixCoord(rowOffsetCurLoop, 0)); | ||
| 414 | + auto gUpdateCurLoop = gUpdate[offsetUpdate]; | ||
| 415 | + auto layoutUpdateCurLoop = layoutUpdate.GetTileLayout(MatrixCoord(rowActualCurLoop, embed)); | ||
| 416 | + | ||
| 417 | + proTokenIdx = rowOffsetLoop % qSThisSubBlock; | ||
| 418 | + proTokenNum = AscendC::Std::min(rowActualCurLoop, (qSThisSubBlock - proTokenIdx)) % qSThisSubBlock; | ||
| 419 | + integralHeadNum = (rowActualCurLoop - proTokenNum) / qSThisSubBlock; | ||
| 420 | + epiTokenNum = rowActualCurLoop - proTokenNum - integralHeadNum * qSThisSubBlock; | ||
| 421 | + | ||
| 422 | + SubCoreCompute( | ||
| 423 | + gOutputCurLoop, | ||
| 424 | + gInputCurLoop, | ||
| 425 | + gUpdateCurLoop, | ||
| 426 | + gLseThisSubBlock, | ||
| 427 | + layoutOutputCurLoop, | ||
| 428 | + layoutInputCurLoop, | ||
| 429 | + layoutUpdateCurLoop, | ||
| 430 | + layoutLse, | ||
| 431 | + qNThisSubBlock, | ||
| 432 | + qSThisSubBlock, | ||
| 433 | + inRowActualThisSubBlock, | ||
| 434 | + isFirstStackTile, | ||
| 435 | + isLastStackTile, | ||
| 436 | + curStackTileMod, | ||
| 437 | + needRowLoop, | ||
| 438 | + (rowLoopIdx == rowLoop - 1U), | ||
| 439 | + rowOffsetLoop, | ||
| 440 | + proTokenIdx, | ||
| 441 | + proTokenNum, | ||
| 442 | + epiTokenNum, | ||
| 443 | + integralHeadNum); | ||
| 444 | + } | ||
| 445 | + } | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | +private: | ||
| 449 | + AscendC::LocalTensor<float> loUbTensor; | ||
| 450 | + AscendC::LocalTensor<float> dmUbTensor; | ||
| 451 | + AscendC::LocalTensor<float> hmUbTensor; | ||
| 452 | + AscendC::LocalTensor<float> glUbTensor; | ||
| 453 | + AscendC::LocalTensor<float> tvUbTensor; | ||
| 454 | + AscendC::LocalTensor<ElementOutput> goUbTensor16; | ||
| 455 | + AscendC::LocalTensor<float> goUbTensor32; | ||
| 456 | + AscendC::LocalTensor<float> gmUbTensor; | ||
| 457 | + AscendC::LocalTensor<float> lse32_ubuf_tensor; | ||
| 458 | +}; | ||
| 459 | +} | ||
| 460 | + | ||
| 461 | + | ||
| @@ -0,0 +1,479 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +namespace NpuArch::Epilogue::Block { | ||
| 24 | + | ||
| 25 | +template < | ||
| 26 | + class ElementO_, | ||
| 27 | + class ElementOTmp_, | ||
| 28 | + class ElementS_, | ||
| 29 | + class TileCopy_, | ||
| 30 | + class OTmpSrcPos_> | ||
| 31 | +class BlockEpilogue< | ||
| 32 | + EpilogueAtlasA5BsaRescaleO, | ||
| 33 | + ElementO_, | ||
| 34 | + ElementOTmp_, | ||
| 35 | + ElementS_, | ||
| 36 | + TileCopy_, | ||
| 37 | + OTmpSrcPos_> | ||
| 38 | +{ | ||
| 39 | +public: | ||
| 40 | + using DispatchPolicy = EpilogueAtlasA5BsaRescaleO; | ||
| 41 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 42 | + using ElementO = ElementO_; | ||
| 43 | + using ElementOTmp = ElementOTmp_; | ||
| 44 | + using SMDtype = ElementS_; | ||
| 45 | + using TileCopy = TileCopy_; | ||
| 46 | + using OTmpSrcPos = OTmpSrcPos_; | ||
| 47 | + | ||
| 48 | + using CopyUbToGmO = typename TileCopy::CopyUbToGmO; | ||
| 49 | + | ||
| 50 | + static constexpr uint32_t UB_OTMP_BUF_STAGES = 2; | ||
| 51 | + static constexpr uint32_t UB_UINT8_BLOCK_SIZE = 32768; | ||
| 52 | + static constexpr uint32_t DM_UB_GLOBAL_ELEM_NUM = 64 * 2; //! 2* for 11 22 ... 32,32 | ||
| 53 | + static constexpr uint32_t RESCALE_ROW_MAX_ELEM_NUM = 64; | ||
| 54 | + static constexpr uint32_t RESCALE_COL_MAX_ELEM_NUM = 128; | ||
| 55 | + static constexpr uint32_t RESCALE_VREG_SIZE = 256 / sizeof(ElementOTmp); | ||
| 56 | + static constexpr bool DEQ = true; | ||
| 57 | + | ||
| 58 | + __aicore__ inline | ||
| 59 | + BlockEpilogue(Arch::Resource<ArchTag> &resource, uint32_t embed_ = 128) | ||
| 60 | + { | ||
| 61 | + constexpr uint32_t LO_UB_TENSOR_OFFSET = 4 * UB_UINT8_BLOCK_SIZE; | ||
| 62 | + constexpr uint32_t GO_UB_TENSOR_OFFSET = 6 * UB_UINT8_BLOCK_SIZE; | ||
| 63 | + constexpr uint32_t LM_UB_TENSOR_OFFSET = 7 * UB_UINT8_BLOCK_SIZE; | ||
| 64 | + constexpr uint32_t GM_UB_TENSOR_OFFSET = LM_UB_TENSOR_OFFSET + 128 * sizeof(float); | ||
| 65 | + constexpr uint32_t DM_UB_TENSOR_OFFSET = GM_UB_TENSOR_OFFSET + 128 * sizeof(float); | ||
| 66 | + constexpr uint32_t LL_UB_TENSOR_OFFSET = DM_UB_TENSOR_OFFSET + 3 * 128 * sizeof(float); | ||
| 67 | + constexpr uint32_t GL_UB_TENSOR_OFFSET = LL_UB_TENSOR_OFFSET + 128 * sizeof(float); | ||
| 68 | + | ||
| 69 | + for (uint32_t i = 0; i < UB_OTMP_BUF_STAGES; i++) { | ||
| 70 | + loUbTensor[i] = resource.ubBuf.template GetBufferByByte<ElementOTmp>( | ||
| 71 | + LO_UB_TENSOR_OFFSET + i * UB_UINT8_BLOCK_SIZE); | ||
| 72 | + } | ||
| 73 | + goUbTensor32 = resource.ubBuf.template GetBufferByByte<ElementOTmp>(GO_UB_TENSOR_OFFSET); | ||
| 74 | + goUbTensor16 = resource.ubBuf.template GetBufferByByte<ElementO>(GO_UB_TENSOR_OFFSET); | ||
| 75 | + glUbTensor32 = resource.ubBuf.template GetBufferByByte<float>(GL_UB_TENSOR_OFFSET); | ||
| 76 | + dmUbTensor32 = resource.ubBuf.template GetBufferByByte<float>(DM_UB_TENSOR_OFFSET); | ||
| 77 | + scaleTensor = resource.ubBuf.template GetBufferByByte<float>(LM_UB_TENSOR_OFFSET + 4096 * 2 + embed_ * sizeof(float)); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + __aicore__ inline | ||
| 81 | + ~BlockEpilogue() | ||
| 82 | + { | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 86 | + __aicore__ inline | ||
| 87 | + void SetCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 88 | + { | ||
| 89 | + if constexpr (MODE == 4U) { | ||
| 90 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlag); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 95 | + __aicore__ inline | ||
| 96 | + void WaitCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 97 | + { | ||
| 98 | + if constexpr (MODE == 4U) { | ||
| 99 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlag); | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + template <class TensorDst> | ||
| 104 | + __aicore__ inline | ||
| 105 | + void SubCoreCompute(const TensorDst &gOTensor, | ||
| 106 | + uint32_t curTileMod, | ||
| 107 | + uint32_t ubOTmpBufId, | ||
| 108 | + bool isFirstKvSTile, | ||
| 109 | + bool isLastKvSTile, | ||
| 110 | + uint32_t colNumOri, | ||
| 111 | + Arch::CrossCoreFlag mm2ToReFlag) | ||
| 112 | + { | ||
| 113 | + __ubuf__ ElementOTmp *goUb = (__ubuf__ ElementOTmp *) goUbTensor32.GetPhyAddr(); | ||
| 114 | + __ubuf__ ElementOTmp *loUb = (__ubuf__ ElementOTmp *) loUbTensor[ubOTmpBufId].GetPhyAddr(); | ||
| 115 | + __ubuf__ ElementOTmp *glUb = ( __ubuf__ ElementOTmp *) glUbTensor32.GetPhyAddr(); | ||
| 116 | + __ubuf__ ElementOTmp *dmUb = (__ubuf__ ElementOTmp *) dmUbTensor32[curTileMod * DM_UB_GLOBAL_ELEM_NUM].GetPhyAddr(); | ||
| 117 | + __ubuf__ ElementOTmp *scaleUb = (__ubuf__ ElementOTmp *)scaleTensor.GetPhyAddr(); | ||
| 118 | + | ||
| 119 | + WaitCrossCoreSync<4, PIPE_V>(mm2ToReFlag); | ||
| 120 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 121 | + | ||
| 122 | + if (isFirstKvSTile) { | ||
| 123 | + if (!isLastKvSTile) { | ||
| 124 | + if constexpr (DEQ) { | ||
| 125 | + DeqLocalO<ElementOTmp, 128, DEQ>(goUb, loUb, scaleUb, rowNumCurSubCore); AscendC::PipeBarrier<PIPE_V>(); | ||
| 126 | + } else { | ||
| 127 | + AscendC::DataCopy(goUbTensor32, loUbTensor[ubOTmpBufId], rowNumCurSubCore * colNumOri); AscendC::PipeBarrier<PIPE_V>(); | ||
| 128 | + } | ||
| 129 | + } else { // go = lo div sum | ||
| 130 | + DivFuncLastAndFirst<ElementOTmp, 128, DEQ>(goUb, loUb, glUb, scaleUb, rowNumCurSubCore); | ||
| 131 | + } | ||
| 132 | + } else if (!isLastKvSTile) { | ||
| 133 | + RescaleFunc<ElementOTmp, 128, DEQ>(goUb, loUb, dmUb, scaleUb, rowNumCurSubCore); | ||
| 134 | + } else { | ||
| 135 | + RescaleFuncLastNotFirst<ElementOTmp, 128, DEQ>(goUb, loUb, dmUb, glUb, scaleUb, rowNumCurSubCore); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + // release lo buf | ||
| 139 | + SetCrossCoreSync<4, PIPE_V>(mm2ToReFlag); | ||
| 140 | + if (isLastKvSTile) { | ||
| 141 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 142 | + if constexpr (std::is_same<ElementO, bfloat16_t>::value) { | ||
| 143 | + AscendC::Cast( | ||
| 144 | + goUbTensor16, goUbTensor32, | ||
| 145 | + AscendC::RoundMode::CAST_RINT, | ||
| 146 | + rowNumCurSubCore * colNumOri); | ||
| 147 | + } else { | ||
| 148 | + AscendC::Cast( | ||
| 149 | + goUbTensor16, goUbTensor32, | ||
| 150 | + AscendC::RoundMode::CAST_NONE, | ||
| 151 | + rowNumCurSubCore * colNumOri); | ||
| 152 | + } | ||
| 153 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID0); | ||
| 154 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID0); | ||
| 155 | + DataCopy(gOTensor[rowOffsetCurSubCore * colNumOri], goUbTensor16, rowNumCurSubCore * colNumOri); | ||
| 156 | + } | ||
| 157 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + template <typename T=float, uint32_t colStride=128, bool DEQ=false> | ||
| 161 | + __simd_vf__ inline void RescaleFunc(__ubuf__ T *goUb, __ubuf__ T *loUb, __ubuf__ T *dmUb, __ubuf__ T *scaleUb, | ||
| 162 | + uint32_t row) | ||
| 163 | + { | ||
| 164 | + using namespace AscendC::MicroAPI; | ||
| 165 | + | ||
| 166 | + RegTensor<float> dmVreg0, dmVreg1, scaleVreg0, scaleVreg1; | ||
| 167 | + RegTensor<float> goPreVreg0, goPreVreg0_2, goPreVreg1, goPreVreg1_2; | ||
| 168 | + RegTensor<float> loVreg0, loVreg0_2, loVreg1, loVreg1_2; | ||
| 169 | + RegTensor<float> mulVreg0, mulVreg0_2, mulVreg1, mulVreg1_2; | ||
| 170 | + RegTensor<float> goCurVreg0, goCurVreg0_2, goCurVreg1, goCurVreg1_2; | ||
| 171 | + | ||
| 172 | + MaskReg pregFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 173 | + constexpr uint32_t vlElemNum = 64; | ||
| 174 | + | ||
| 175 | + uint32_t halfRow = (row + 1) / 2; // = 32 | ||
| 176 | + | ||
| 177 | + // 循环 32 次,每次处理 row_i 和 row_{i+32} | ||
| 178 | + if constexpr (DEQ) { | ||
| 179 | + LoadAlign<T, LoadDist::DIST_NORM>(scaleVreg0, scaleUb); // col0 | ||
| 180 | + LoadAlign<T, LoadDist::DIST_NORM>(scaleVreg1, scaleUb + vlElemNum); //col1 | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + for (uint16_t i = 0; i < halfRow; i++) { | ||
| 184 | + uint32_t row1_idx = i + halfRow; | ||
| 185 | + | ||
| 186 | + uint32_t baseOffset0 = i * colStride; | ||
| 187 | + uint32_t secondOffset0 = baseOffset0 + vlElemNum; | ||
| 188 | + uint32_t baseOffset1 = row1_idx * colStride; | ||
| 189 | + uint32_t secondOffset1 = baseOffset1 + vlElemNum; | ||
| 190 | + | ||
| 191 | + // Load scalars and broadcast | ||
| 192 | + //! 2* for 11 22 ... 32,32 | ||
| 193 | + LoadAlign<T, LoadDist::DIST_BRC_B32>(dmVreg0, dmUb + 2*i); | ||
| 194 | + LoadAlign<T, LoadDist::DIST_BRC_B32>(dmVreg1, dmUb + 2*row1_idx); | ||
| 195 | + | ||
| 196 | + // Load Row i | ||
| 197 | + LoadAlign<T, LoadDist::DIST_NORM>(goPreVreg0, goUb + baseOffset0); | ||
| 198 | + LoadAlign<T, LoadDist::DIST_NORM>(goPreVreg0_2, goUb + secondOffset0); | ||
| 199 | + LoadAlign<T, LoadDist::DIST_NORM>(loVreg0, loUb + baseOffset0); | ||
| 200 | + LoadAlign<T, LoadDist::DIST_NORM>(loVreg0_2, loUb + secondOffset0); | ||
| 201 | + | ||
| 202 | + // Load Row i+32 | ||
| 203 | + LoadAlign<T, LoadDist::DIST_NORM>(goPreVreg1, goUb + baseOffset1); | ||
| 204 | + LoadAlign<T, LoadDist::DIST_NORM>(goPreVreg1_2, goUb + secondOffset1); | ||
| 205 | + LoadAlign<T, LoadDist::DIST_NORM>(loVreg1, loUb + baseOffset1); | ||
| 206 | + LoadAlign<T, LoadDist::DIST_NORM>(loVreg1_2, loUb + secondOffset1); | ||
| 207 | + | ||
| 208 | + // Multiply (4-issue) | ||
| 209 | + Mul(mulVreg0, goPreVreg0, dmVreg0, pregFull); | ||
| 210 | + Mul(mulVreg0_2, goPreVreg0_2, dmVreg0, pregFull); | ||
| 211 | + Mul(mulVreg1, goPreVreg1, dmVreg1, pregFull); | ||
| 212 | + Mul(mulVreg1_2, goPreVreg1_2, dmVreg1, pregFull); | ||
| 213 | + | ||
| 214 | + if constexpr (DEQ) { | ||
| 215 | + MulDstAdd(loVreg0, scaleVreg0, mulVreg0, pregFull); | ||
| 216 | + MulDstAdd(loVreg0_2, scaleVreg1, mulVreg0_2, pregFull); | ||
| 217 | + MulDstAdd(loVreg1, scaleVreg0, mulVreg1, pregFull); | ||
| 218 | + MulDstAdd(loVreg1_2, scaleVreg1, mulVreg1_2, pregFull); | ||
| 219 | + } else { | ||
| 220 | + Add(loVreg0, mulVreg0, loVreg0, pregFull); | ||
| 221 | + Add(loVreg0_2, mulVreg0_2, loVreg0_2, pregFull); | ||
| 222 | + Add(loVreg1, mulVreg1, loVreg1, pregFull); | ||
| 223 | + Add(loVreg1_2, mulVreg1_2, loVreg1_2, pregFull); | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + // Store (4-issue) | ||
| 227 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + baseOffset0, loVreg0, pregFull); | ||
| 228 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + secondOffset0, loVreg0_2, pregFull); | ||
| 229 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + baseOffset1, loVreg1, pregFull); | ||
| 230 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + secondOffset1, loVreg1_2, pregFull); | ||
| 231 | + } | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + template <typename T=float, uint32_t colStride=128, bool DEQ=false> | ||
| 235 | + __simd_vf__ inline void RescaleFuncLastNotFirst(__ubuf__ T *goUb, __ubuf__ T *loUb, | ||
| 236 | + __ubuf__ T *dmUb, __ubuf__ T *glUb, | ||
| 237 | + __ubuf__ T *scaleUb, | ||
| 238 | + uint32_t row) | ||
| 239 | + { | ||
| 240 | + using namespace AscendC::MicroAPI; | ||
| 241 | + | ||
| 242 | + RegTensor<float> dmVreg0, glVreg0, dmVreg1, glVreg1; | ||
| 243 | + RegTensor<float> scaleVreg0, scaleVreg1; // 增加 scale 寄存器 | ||
| 244 | + RegTensor<float> goPreVreg0, goPreVreg0_2, goPreVreg1, goPreVreg1_2; | ||
| 245 | + RegTensor<float> loVreg0, loVreg0_2, loVreg1, loVreg1_2; | ||
| 246 | + RegTensor<float> mulVreg0, mulVreg0_2, mulVreg1, mulVreg1_2; | ||
| 247 | + RegTensor<float> goCurVreg0, goCurVreg0_2, goCurVreg1, goCurVreg1_2; | ||
| 248 | + RegTensor<float> divVreg0, divVreg0_2, divVreg1, divVreg1_2; | ||
| 249 | + | ||
| 250 | + MaskReg pregFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 251 | + constexpr uint32_t vlElemNum = 64; | ||
| 252 | + | ||
| 253 | + uint32_t halfRow = (row + 1) / 2; // = 32 | ||
| 254 | + | ||
| 255 | + // 若开启反量化,在循环外一次性加载 per-channel scale | ||
| 256 | + if constexpr (DEQ) { | ||
| 257 | + LoadAlign<T, LoadDist::DIST_NORM>(scaleVreg0, scaleUb); // col0 | ||
| 258 | + LoadAlign<T, LoadDist::DIST_NORM>(scaleVreg1, scaleUb + vlElemNum); // col1 | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | + for (uint16_t i = 0; i < halfRow; i++) { | ||
| 262 | + uint32_t row1_idx = i + halfRow; | ||
| 263 | + | ||
| 264 | + uint32_t baseOffset0 = i * colStride; | ||
| 265 | + uint32_t secondOffset0 = baseOffset0 + vlElemNum; | ||
| 266 | + uint32_t baseOffset1 = row1_idx * colStride; | ||
| 267 | + uint32_t secondOffset1 = baseOffset1 + vlElemNum; | ||
| 268 | + | ||
| 269 | + // Load scalars (i and i+32) | ||
| 270 | + //! 2* for 11 22 ... 32,32 | ||
| 271 | + LoadAlign<T, LoadDist::DIST_BRC_B32>(dmVreg0, dmUb + 2*i); | ||
| 272 | + LoadAlign<T, LoadDist::DIST_BRC_B32>(glVreg0, glUb + 2*i); | ||
| 273 | + LoadAlign<T, LoadDist::DIST_BRC_B32>(dmVreg1, dmUb + 2*row1_idx); | ||
| 274 | + LoadAlign<T, LoadDist::DIST_BRC_B32>(glVreg1, glUb + 2*row1_idx); | ||
| 275 | + | ||
| 276 | + // Load Data | ||
| 277 | + LoadAlign<T, LoadDist::DIST_NORM>(goPreVreg0, goUb + baseOffset0); | ||
| 278 | + LoadAlign<T, LoadDist::DIST_NORM>(goPreVreg0_2, goUb + secondOffset0); | ||
| 279 | + LoadAlign<T, LoadDist::DIST_NORM>(goPreVreg1, goUb + baseOffset1); | ||
| 280 | + LoadAlign<T, LoadDist::DIST_NORM>(goPreVreg1_2, goUb + secondOffset1); | ||
| 281 | + | ||
| 282 | + LoadAlign<T, LoadDist::DIST_NORM>(loVreg0, loUb + baseOffset0); | ||
| 283 | + LoadAlign<T, LoadDist::DIST_NORM>(loVreg0_2, loUb + secondOffset0); | ||
| 284 | + LoadAlign<T, LoadDist::DIST_NORM>(loVreg1, loUb + baseOffset1); | ||
| 285 | + LoadAlign<T, LoadDist::DIST_NORM>(loVreg1_2, loUb + secondOffset1); | ||
| 286 | + | ||
| 287 | + // Muls: goPre * dm | ||
| 288 | + Mul(mulVreg0, goPreVreg0, dmVreg0, pregFull); | ||
| 289 | + Mul(mulVreg0_2, goPreVreg0_2, dmVreg0, pregFull); | ||
| 290 | + Mul(mulVreg1, goPreVreg1, dmVreg1, pregFull); | ||
| 291 | + Mul(mulVreg1_2, goPreVreg1_2, dmVreg1, pregFull); | ||
| 292 | + | ||
| 293 | + // Dequantization: Local * scale + mulvreg | ||
| 294 | + // dstReg与srcReg0相乘后与srcReg1相加 | ||
| 295 | + if constexpr (DEQ) { | ||
| 296 | + MulDstAdd(loVreg0, scaleVreg0, mulVreg0, pregFull); | ||
| 297 | + MulDstAdd(loVreg0_2, scaleVreg1, mulVreg0_2, pregFull); | ||
| 298 | + MulDstAdd(loVreg1, scaleVreg0, mulVreg1, pregFull); | ||
| 299 | + MulDstAdd(loVreg1_2, scaleVreg1, mulVreg1_2, pregFull); | ||
| 300 | + } else { | ||
| 301 | + Add(loVreg0, mulVreg0, loVreg0, pregFull); | ||
| 302 | + Add(loVreg0_2, mulVreg0_2, loVreg0_2, pregFull); | ||
| 303 | + Add(loVreg1, mulVreg1, loVreg1, pregFull); | ||
| 304 | + Add(loVreg1_2, mulVreg1_2, loVreg1_2, pregFull); | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + Div(divVreg0, loVreg0, glVreg0, pregFull); | ||
| 308 | + Div(divVreg0_2, loVreg0_2, glVreg0, pregFull); | ||
| 309 | + Div(divVreg1, loVreg1, glVreg1, pregFull); | ||
| 310 | + Div(divVreg1_2, loVreg1_2, glVreg1, pregFull); | ||
| 311 | + | ||
| 312 | + // Stores | ||
| 313 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + baseOffset0, divVreg0, pregFull); | ||
| 314 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + secondOffset0, divVreg0_2, pregFull); | ||
| 315 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + baseOffset1, divVreg1, pregFull); | ||
| 316 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + secondOffset1, divVreg1_2, pregFull); | ||
| 317 | + } | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + template <typename T=float, uint32_t colStride=128, bool DEQ=false> | ||
| 321 | + __simd_vf__ inline void DivFuncLastAndFirst(__ubuf__ T *goUb, __ubuf__ T *loUb, __ubuf__ T *glUb, | ||
| 322 | + __ubuf__ T *scaleUb, // 保持接口一致性 | ||
| 323 | + uint32_t row) | ||
| 324 | + { | ||
| 325 | + using namespace AscendC::MicroAPI; | ||
| 326 | + | ||
| 327 | + RegTensor<float> goCurVreg0, goCurVreg0_2, goCurVreg1, goCurVreg1_2; | ||
| 328 | + RegTensor<float> glVreg0, glVreg1; | ||
| 329 | + RegTensor<float> scaleVreg0, scaleVreg1; // 仅做声明备用 | ||
| 330 | + RegTensor<float> divVreg0, divVreg0_2, divVreg1, divVreg1_2; | ||
| 331 | + | ||
| 332 | + MaskReg pregFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 333 | + constexpr uint32_t vlElemNum = 64; | ||
| 334 | + | ||
| 335 | + if constexpr (colStride==128) { | ||
| 336 | + uint32_t halfRow = (row + 1) / 2; // = 32 | ||
| 337 | + | ||
| 338 | + if constexpr (DEQ) { | ||
| 339 | + LoadAlign<T, LoadDist::DIST_NORM>(scaleVreg0, scaleUb); | ||
| 340 | + LoadAlign<T, LoadDist::DIST_NORM>(scaleVreg1, scaleUb + vlElemNum); | ||
| 341 | + } | ||
| 342 | + for (uint16_t i = 0; i < halfRow; i++) { | ||
| 343 | + uint32_t row1_idx = i + halfRow; | ||
| 344 | + | ||
| 345 | + uint32_t baseOffset0 = i * colStride; | ||
| 346 | + uint32_t secondOffset0 = baseOffset0 + vlElemNum; | ||
| 347 | + uint32_t baseOffset1 = row1_idx * colStride; | ||
| 348 | + uint32_t secondOffset1 = baseOffset1 + vlElemNum; | ||
| 349 | + //! 2* for 11 22 ... 32,32 | ||
| 350 | + LoadAlign<T, LoadDist::DIST_BRC_B32>(glVreg0, glUb + 2*i); | ||
| 351 | + LoadAlign<T, LoadDist::DIST_BRC_B32>(glVreg1, glUb + 2*row1_idx); | ||
| 352 | + | ||
| 353 | + LoadAlign<T, LoadDist::DIST_NORM>(goCurVreg0, loUb + baseOffset0); | ||
| 354 | + LoadAlign<T, LoadDist::DIST_NORM>(goCurVreg0_2, loUb + secondOffset0); | ||
| 355 | + LoadAlign<T, LoadDist::DIST_NORM>(goCurVreg1, loUb + baseOffset1); | ||
| 356 | + LoadAlign<T, LoadDist::DIST_NORM>(goCurVreg1_2, loUb + secondOffset1); | ||
| 357 | + | ||
| 358 | + if constexpr (DEQ) { | ||
| 359 | + Mul(goCurVreg0, goCurVreg0, scaleVreg0, pregFull); | ||
| 360 | + Mul(goCurVreg0_2, goCurVreg0_2, scaleVreg1, pregFull); | ||
| 361 | + Mul(goCurVreg1, goCurVreg1, scaleVreg0, pregFull); | ||
| 362 | + Mul(goCurVreg1_2, goCurVreg1_2, scaleVreg1, pregFull); | ||
| 363 | + } | ||
| 364 | + | ||
| 365 | + Div(divVreg0, goCurVreg0, glVreg0, pregFull); | ||
| 366 | + Div(divVreg0_2, goCurVreg0_2, glVreg0, pregFull); | ||
| 367 | + Div(divVreg1, goCurVreg1, glVreg1, pregFull); | ||
| 368 | + Div(divVreg1_2, goCurVreg1_2, glVreg1, pregFull); | ||
| 369 | + | ||
| 370 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + baseOffset0, divVreg0, pregFull); | ||
| 371 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + secondOffset0, divVreg0_2, pregFull); | ||
| 372 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + baseOffset1, divVreg1, pregFull); | ||
| 373 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + secondOffset1, divVreg1_2, pregFull); | ||
| 374 | + } | ||
| 375 | + } | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + template <typename T=float, uint32_t colStride=128, bool DEQ=false> | ||
| 379 | + __simd_vf__ inline void DeqLocalO(__ubuf__ T *goUb, __ubuf__ T *loUb, | ||
| 380 | + __ubuf__ T *scaleUb, | ||
| 381 | + uint32_t row) | ||
| 382 | + { | ||
| 383 | + using namespace AscendC::MicroAPI; | ||
| 384 | + | ||
| 385 | + RegTensor<float> goCurVreg0, goCurVreg0_2, goCurVreg1, goCurVreg1_2; | ||
| 386 | + RegTensor<float> scaleVreg0, scaleVreg1; | ||
| 387 | + | ||
| 388 | + MaskReg pregFull = CreateMask<float, MaskPattern::ALL>(); | ||
| 389 | + constexpr uint32_t vlElemNum = 64; | ||
| 390 | + | ||
| 391 | + if constexpr (colStride==128) { | ||
| 392 | + uint32_t halfRow = (row + 1) / 2; // = 32 | ||
| 393 | + | ||
| 394 | + if constexpr (DEQ) { | ||
| 395 | + LoadAlign<T, LoadDist::DIST_NORM>(scaleVreg0, scaleUb); | ||
| 396 | + LoadAlign<T, LoadDist::DIST_NORM>(scaleVreg1, scaleUb + vlElemNum); | ||
| 397 | + } | ||
| 398 | + for (uint16_t i = 0; i < halfRow; i++) { | ||
| 399 | + uint32_t row1_idx = i + halfRow; | ||
| 400 | + | ||
| 401 | + uint32_t baseOffset0 = i * colStride; | ||
| 402 | + uint32_t secondOffset0 = baseOffset0 + vlElemNum; | ||
| 403 | + uint32_t baseOffset1 = row1_idx * colStride; | ||
| 404 | + uint32_t secondOffset1 = baseOffset1 + vlElemNum; | ||
| 405 | + | ||
| 406 | + LoadAlign<T, LoadDist::DIST_NORM>(goCurVreg0, loUb + baseOffset0); | ||
| 407 | + LoadAlign<T, LoadDist::DIST_NORM>(goCurVreg0_2, loUb + secondOffset0); | ||
| 408 | + LoadAlign<T, LoadDist::DIST_NORM>(goCurVreg1, loUb + baseOffset1); | ||
| 409 | + LoadAlign<T, LoadDist::DIST_NORM>(goCurVreg1_2, loUb + secondOffset1); | ||
| 410 | + | ||
| 411 | + if constexpr (DEQ) { | ||
| 412 | + Mul(goCurVreg0, goCurVreg0, scaleVreg0, pregFull); | ||
| 413 | + Mul(goCurVreg0_2, goCurVreg0_2, scaleVreg1, pregFull); | ||
| 414 | + Mul(goCurVreg1, goCurVreg1, scaleVreg0, pregFull); | ||
| 415 | + Mul(goCurVreg1_2, goCurVreg1_2, scaleVreg1, pregFull); | ||
| 416 | + } | ||
| 417 | + | ||
| 418 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + baseOffset0, goCurVreg0, pregFull); | ||
| 419 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + secondOffset0, goCurVreg0_2, pregFull); | ||
| 420 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + baseOffset1, goCurVreg1, pregFull); | ||
| 421 | + StoreAlign<T, StoreDist::DIST_NORM_B32>(goUb + secondOffset1, goCurVreg1_2, pregFull); | ||
| 422 | + } | ||
| 423 | + } | ||
| 424 | + } | ||
| 425 | + | ||
| 426 | + template <class TensorDst> | ||
| 427 | + __aicore__ inline | ||
| 428 | + void operator()(const TensorDst &gOTensor, | ||
| 429 | + GemmCoord actualOriShape, | ||
| 430 | + uint32_t curTileMod, | ||
| 431 | + uint32_t gatheredKvSTileIdx, | ||
| 432 | + bool isFirstKvSTile, | ||
| 433 | + bool isLastKvSTile, | ||
| 434 | + Arch::CrossCoreFlag mm2ToReFlag) | ||
| 435 | + { | ||
| 436 | + uint32_t rowNumOri = actualOriShape[0]; | ||
| 437 | + uint32_t colNumOri = actualOriShape[1]; | ||
| 438 | + constexpr uint32_t FP8_BLOCK_SIZE = 32; | ||
| 439 | + if (rowNumOri <= FP8_BLOCK_SIZE) { | ||
| 440 | + rowNumCurSubCore = (subBlockIdx == 0) ? rowNumOri : 0; | ||
| 441 | + } else { | ||
| 442 | + uint32_t mhalf = (rowNumOri + subBlockNum -1) / subBlockNum; | ||
| 443 | + uint32_t mAlign = (mhalf > FP8_BLOCK_SIZE) ? RoundUp(mhalf, FP8_BLOCK_SIZE) : FP8_BLOCK_SIZE; | ||
| 444 | + rowNumCurSubCore = (subBlockIdx == 0) ? mAlign : (rowNumOri - mAlign); | ||
| 445 | + } | ||
| 446 | + rowOffsetCurSubCore = subBlockIdx == 0 ? 0: rowNumOri - rowNumCurSubCore; | ||
| 447 | + uint32_t ubOTmpBufId = gatheredKvSTileIdx % UB_OTMP_BUF_STAGES; | ||
| 448 | + | ||
| 449 | + if (rowNumCurSubCore > 0) { | ||
| 450 | + SubCoreCompute( | ||
| 451 | + gOTensor, | ||
| 452 | + curTileMod, | ||
| 453 | + ubOTmpBufId, | ||
| 454 | + isFirstKvSTile, | ||
| 455 | + isLastKvSTile, | ||
| 456 | + colNumOri, | ||
| 457 | + mm2ToReFlag); | ||
| 458 | + } else { | ||
| 459 | + Arch::CrossCoreWaitFlag<4, PIPE_V>(mm2ToReFlag); | ||
| 460 | + Arch::CrossCoreSetFlag<4, PIPE_V>(mm2ToReFlag); | ||
| 461 | + } | ||
| 462 | + } | ||
| 463 | +private: | ||
| 464 | + AscendC::LocalTensor<ElementOTmp> loUbTensor[UB_OTMP_BUF_STAGES]; | ||
| 465 | + AscendC::LocalTensor<SMDtype> dmUbTensor16; | ||
| 466 | + AscendC::LocalTensor<SMDtype> glUbTensor16; | ||
| 467 | + AscendC::LocalTensor<float> dmUbTensor32; | ||
| 468 | + AscendC::LocalTensor<float> glUbTensor32; | ||
| 469 | + AscendC::LocalTensor<float> scaleTensor; | ||
| 470 | + AscendC::LocalTensor<ElementO> goUbTensor16; | ||
| 471 | + AscendC::LocalTensor<ElementOTmp> goUbTensor32; | ||
| 472 | + | ||
| 473 | + uint32_t subBlockNum = AscendC::GetSubBlockNum(); | ||
| 474 | + uint32_t subBlockIdx = AscendC::GetSubBlockIdx(); | ||
| 475 | + uint32_t rowOffsetCurSubCore = 0; | ||
| 476 | + uint32_t rowNumCurSubCore = 0; | ||
| 477 | +}; | ||
| 478 | +} | ||
| 479 | + | ||
| @@ -0,0 +1,463 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace NpuArch::Epilogue::Block { | ||
| 22 | + | ||
| 23 | +template < | ||
| 24 | + class OutputType_, | ||
| 25 | + class InputType_, | ||
| 26 | + class UpdateType_, | ||
| 27 | + class LseType_, | ||
| 28 | + LseMode LSE_MODE_> | ||
| 29 | +class BlockEpilogue< | ||
| 30 | + EpilogueAtlasA2RescaleO<LSE_MODE_, half>, | ||
| 31 | + OutputType_, | ||
| 32 | + InputType_, | ||
| 33 | + UpdateType_, | ||
| 34 | + LseType_> | ||
| 35 | +{ | ||
| 36 | +public: | ||
| 37 | + // Type aliases | ||
| 38 | + using DispatchPolicy = EpilogueAtlasA2RescaleO<LSE_MODE_, half>; | ||
| 39 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 40 | + | ||
| 41 | + using ElementOutput = typename OutputType_::Element; | ||
| 42 | + using ElementInput = typename InputType_::Element; | ||
| 43 | + using ElementUpdate = typename UpdateType_::Element; | ||
| 44 | + using ElementLse = typename LseType_::Element; | ||
| 45 | + | ||
| 46 | + using LayoutOutput = typename OutputType_::Layout; | ||
| 47 | + using LayoutInput = typename InputType_::Layout; | ||
| 48 | + using LayoutUpdate = typename UpdateType_::Layout; | ||
| 49 | + using LayoutLse = typename LseType_::Layout; | ||
| 50 | + | ||
| 51 | + static constexpr LseMode LSE_MODE = DispatchPolicy::LSE_MODE; | ||
| 52 | + | ||
| 53 | + static constexpr uint32_t HALF_ELENUM_PER_BLK = 16; | ||
| 54 | + static constexpr uint32_t BLOCK_SIZE = 16; | ||
| 55 | + static constexpr uint32_t HALF_ELENUM_PER_VECCALC = 128; | ||
| 56 | + static constexpr uint32_t FLOAT_ELENUM_PER_VECCALC = 64; | ||
| 57 | + static constexpr uint32_t HALF_ELENUM_PER_LINE = 256; | ||
| 58 | + static constexpr uint32_t FLOAT_ELENUM_PER_LINE = 128; | ||
| 59 | + static constexpr uint32_t MULTIPLIER = 2; | ||
| 60 | + static constexpr uint32_t FLOAT_BLOCK_SIZE = 8; | ||
| 61 | + static constexpr uint32_t HALF_BLOCK_SIZE = 16; | ||
| 62 | + static constexpr uint32_t FLOAT_VECTOR_SIZE = 64; | ||
| 63 | + static constexpr uint32_t HALF_VECTOR_SIZE = 128; | ||
| 64 | + static constexpr uint32_t UB_UINT8_VECTOR_SIZE = 1024; | ||
| 65 | + static constexpr uint32_t UB_UINT8_BLOCK_SIZE = 16384; | ||
| 66 | + static constexpr uint32_t HALF_DM_UB_SIZE = 64; | ||
| 67 | + static constexpr uint32_t HALF_LL_UB_SIZE = 256; | ||
| 68 | + static constexpr uint32_t VECTOR_SIZE = 128; | ||
| 69 | + static constexpr uint32_t NUM4 = 4; | ||
| 70 | + static constexpr uint32_t MAX_UB_O_ELEM_NUM = 8192; | ||
| 71 | + static constexpr uint32_t MAX_ROW_NUM_SUB_CORE = 256; | ||
| 72 | + static constexpr uint32_t SIZE_OF_16BIT = 2; | ||
| 73 | + | ||
| 74 | + __aicore__ inline | ||
| 75 | + BlockEpilogue(Arch::Resource<ArchTag> &resource) | ||
| 76 | + { | ||
| 77 | + // Allocate UB space | ||
| 78 | + constexpr uint32_t LO_UB_TENSOR_OFFSET = 8 * UB_UINT8_BLOCK_SIZE; | ||
| 79 | + constexpr uint32_t GO_UB_TENSOR_OFFSET = 9 * UB_UINT8_BLOCK_SIZE; | ||
| 80 | + constexpr uint32_t TV_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE; | ||
| 81 | + | ||
| 82 | + constexpr uint32_t HM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 9 * UB_UINT8_VECTOR_SIZE; | ||
| 83 | + constexpr uint32_t GM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 10 * UB_UINT8_VECTOR_SIZE; | ||
| 84 | + constexpr uint32_t LSE32_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 10 * UB_UINT8_VECTOR_SIZE; | ||
| 85 | + constexpr uint32_t GL_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 12 * UB_UINT8_VECTOR_SIZE; | ||
| 86 | + constexpr uint32_t LSE16_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 12 * UB_UINT8_VECTOR_SIZE; | ||
| 87 | + constexpr uint32_t DM_UB_TENSOR_OFFSET = 10 * UB_UINT8_BLOCK_SIZE + 13 * UB_UINT8_VECTOR_SIZE; | ||
| 88 | + | ||
| 89 | + loUbTensor = resource.ubBuf.template GetBufferByByte<half>(LO_UB_TENSOR_OFFSET); | ||
| 90 | + dmUbTensor = resource.ubBuf.template GetBufferByByte<half>(DM_UB_TENSOR_OFFSET); | ||
| 91 | + glUbTensor = resource.ubBuf.template GetBufferByByte<half>(GL_UB_TENSOR_OFFSET); | ||
| 92 | + tvUbTensor = resource.ubBuf.template GetBufferByByte<half>(TV_UB_TENSOR_OFFSET); | ||
| 93 | + tvUbTensor32 = resource.ubBuf.template GetBufferByByte<float>(TV_UB_TENSOR_OFFSET); | ||
| 94 | + goUbTensor = resource.ubBuf.template GetBufferByByte<ElementOutput>(GO_UB_TENSOR_OFFSET); | ||
| 95 | + hmUbTensor = resource.ubBuf.template GetBufferByByte<half>(HM_UB_TENSOR_OFFSET); | ||
| 96 | + gmUbTensor = resource.ubBuf.template GetBufferByByte<half>(GM_UB_TENSOR_OFFSET); | ||
| 97 | + lse16_ubuf_tensor = resource.ubBuf.template GetBufferByByte<half>(LSE16_UB_TENSOR_OFFSET); | ||
| 98 | + lse32_ubuf_tensor = resource.ubBuf.template GetBufferByByte<float>(LSE32_UB_TENSOR_OFFSET); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + __aicore__ inline | ||
| 102 | + ~BlockEpilogue() {} | ||
| 103 | + | ||
| 104 | + __aicore__ inline | ||
| 105 | + void SetMask(int32_t len) | ||
| 106 | + { | ||
| 107 | + const int32_t MAX_MASK_LEN = 128; | ||
| 108 | + const int32_t HALF_MASK_LEN = 64; | ||
| 109 | + if (len >= MAX_MASK_LEN) { | ||
| 110 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 111 | + return; | ||
| 112 | + } | ||
| 113 | + int32_t highMask = len - HALF_MASK_LEN > 0 ? len - HALF_MASK_LEN : 0; | ||
| 114 | + int32_t lowMask = len - HALF_MASK_LEN >= 0 ? HALF_MASK_LEN : len; | ||
| 115 | + if (len < HALF_MASK_LEN) { | ||
| 116 | + AscendC::SetVectorMask<int8_t>(0x0, ((uint64_t)1 << lowMask) - 1); | ||
| 117 | + } else { | ||
| 118 | + AscendC::SetVectorMask<int8_t>(((uint64_t)1 << highMask) - 1, 0xffffffffffffffff); | ||
| 119 | + } | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + __aicore__ inline | ||
| 123 | + void CopyOToGm(AscendC::GlobalTensor<ElementOutput> gOutput, uint32_t proTokenIdx, uint32_t proTokenNum, | ||
| 124 | + uint32_t epiTokenNum, uint32_t integralHeadNum, uint32_t qSThisSubBlock, uint32_t embed, uint32_t oHiddenSize) | ||
| 125 | + { | ||
| 126 | + uint32_t innerOGmOffset = 0; | ||
| 127 | + uint32_t innerGOUbOffset = 0; | ||
| 128 | + if (proTokenNum != 0U) { | ||
| 129 | + AscendC::DataCopyPad( | ||
| 130 | + gOutput[innerOGmOffset + proTokenIdx * oHiddenSize], | ||
| 131 | + goUbTensor[innerGOUbOffset], | ||
| 132 | + AscendC::DataCopyExtParams( | ||
| 133 | + proTokenNum, embed * SIZE_OF_16BIT, 0, (oHiddenSize - embed) * SIZE_OF_16BIT, 0)); | ||
| 134 | + innerOGmOffset += embed; | ||
| 135 | + innerGOUbOffset += proTokenNum * embed; | ||
| 136 | + } | ||
| 137 | + for (uint32_t qN_idx = 0; qN_idx < integralHeadNum; qN_idx++) { | ||
| 138 | + AscendC::DataCopyPad( | ||
| 139 | + gOutput[innerOGmOffset], | ||
| 140 | + goUbTensor[innerGOUbOffset], | ||
| 141 | + AscendC::DataCopyExtParams( | ||
| 142 | + qSThisSubBlock, embed * SIZE_OF_16BIT, 0, (oHiddenSize - embed) * SIZE_OF_16BIT, 0)); | ||
| 143 | + innerOGmOffset += embed; | ||
| 144 | + innerGOUbOffset += qSThisSubBlock * embed; | ||
| 145 | + } | ||
| 146 | + if (epiTokenNum != 0U) { | ||
| 147 | + AscendC::DataCopyPad( | ||
| 148 | + gOutput[innerOGmOffset], | ||
| 149 | + goUbTensor[innerGOUbOffset], | ||
| 150 | + AscendC::DataCopyExtParams( | ||
| 151 | + epiTokenNum, embed * SIZE_OF_16BIT, 0, (oHiddenSize - embed) * SIZE_OF_16BIT, 0)); | ||
| 152 | + } | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + __aicore__ inline | ||
| 156 | + void SubCoreCompute( | ||
| 157 | + AscendC::GlobalTensor<ElementOutput> gOutput, | ||
| 158 | + AscendC::GlobalTensor<ElementInput> gInput, | ||
| 159 | + AscendC::GlobalTensor<ElementUpdate> gUpdate, | ||
| 160 | + AscendC::GlobalTensor<ElementLse> gLse, | ||
| 161 | + const LayoutOutput &layoutOutput, | ||
| 162 | + const LayoutInput &layoutInput, | ||
| 163 | + const LayoutUpdate &layoutUpdate, | ||
| 164 | + const LayoutLse &layoutLse, | ||
| 165 | + uint32_t qNThisSubBlock, uint32_t qSThisSubBlock, uint32_t totalRowNum, | ||
| 166 | + uint32_t isFirstStackTile, uint32_t isLastStackTile, uint32_t curStackTileMod, | ||
| 167 | + uint32_t needRowLoop, uint32_t isLastRowLoop, uint32_t rowOffsetLoop, | ||
| 168 | + uint32_t proTokenIdx, uint32_t proTokenNum, uint32_t epiTokenNum, uint32_t integralHeadNum) | ||
| 169 | + { | ||
| 170 | + uint32_t curRowNum = layoutInput.shape(0); | ||
| 171 | + uint32_t embed = layoutInput.shape(1); | ||
| 172 | + uint32_t embedRound = layoutInput.stride(0); | ||
| 173 | + uint32_t curRowNumRound = RoundUp(curRowNum, HALF_BLOCK_SIZE); | ||
| 174 | + uint32_t qSBlockSize = layoutOutput.shape(0); | ||
| 175 | + uint32_t oHiddenSize = layoutOutput.shape(1); | ||
| 176 | + uint32_t stride = layoutLse.shape(1); | ||
| 177 | + uint32_t dmUbOffsetCurStackTile = curStackTileMod * MAX_ROW_NUM_SUB_CORE + rowOffsetLoop; | ||
| 178 | + | ||
| 179 | + if (!isFirstStackTile) { | ||
| 180 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID3); | ||
| 181 | + AscendC::DataCopy( | ||
| 182 | + loUbTensor, gInput, AscendC::DataCopyParams(1, curRowNum * embedRound / HALF_BLOCK_SIZE, 0, 0)); | ||
| 183 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 184 | + } | ||
| 185 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID6); | ||
| 186 | + if (!isFirstStackTile) { | ||
| 187 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 188 | + AscendC::Brcb( | ||
| 189 | + tvUbTensor.ReinterpretCast<uint16_t>(), | ||
| 190 | + dmUbTensor[dmUbOffsetCurStackTile].ReinterpretCast<uint16_t>(), | ||
| 191 | + curRowNumRound / FLOAT_BLOCK_SIZE, | ||
| 192 | + AscendC::BrcbRepeatParams(1, 8)); | ||
| 193 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 194 | + if (needRowLoop) { | ||
| 195 | + AscendC::DataCopy( | ||
| 196 | + goUbTensor, gUpdate, | ||
| 197 | + AscendC::DataCopyParams(1, curRowNum * embedRound / HALF_BLOCK_SIZE, 0, 0)); | ||
| 198 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID1); | ||
| 199 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID1); | ||
| 200 | + } | ||
| 201 | + // *** go = go * dm_block | ||
| 202 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 203 | + for (uint32_t vmul_idx = 0; vmul_idx < embed / HALF_VECTOR_SIZE; ++vmul_idx) { | ||
| 204 | + AscendC::Mul<half, false>( | ||
| 205 | + goUbTensor[vmul_idx * HALF_VECTOR_SIZE], | ||
| 206 | + goUbTensor[vmul_idx * HALF_VECTOR_SIZE], | ||
| 207 | + tvUbTensor, | ||
| 208 | + (uint64_t)0, | ||
| 209 | + curRowNum, | ||
| 210 | + AscendC::BinaryRepeatParams( | ||
| 211 | + 1, 1, 0, embedRound / HALF_BLOCK_SIZE, embedRound / HALF_BLOCK_SIZE, 1)); | ||
| 212 | + } | ||
| 213 | + if (embed % HALF_VECTOR_SIZE > 0) { | ||
| 214 | + SetMask(embed % HALF_VECTOR_SIZE); | ||
| 215 | + AscendC::Mul<half, false>( | ||
| 216 | + goUbTensor[embed / HALF_VECTOR_SIZE * HALF_VECTOR_SIZE], | ||
| 217 | + goUbTensor[embed / HALF_VECTOR_SIZE * HALF_VECTOR_SIZE], | ||
| 218 | + tvUbTensor, | ||
| 219 | + (uint64_t)0, | ||
| 220 | + curRowNum, | ||
| 221 | + AscendC::BinaryRepeatParams( | ||
| 222 | + 1, 1, 0, embedRound / HALF_BLOCK_SIZE, embedRound / HALF_BLOCK_SIZE, 1)); | ||
| 223 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 224 | + } | ||
| 225 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 226 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 227 | + // *** go = lo + go | ||
| 228 | + AscendC::Add<half, false>( | ||
| 229 | + goUbTensor, | ||
| 230 | + goUbTensor, | ||
| 231 | + loUbTensor, | ||
| 232 | + (uint64_t)0, | ||
| 233 | + (curRowNum * embedRound + HALF_VECTOR_SIZE - 1) / HALF_VECTOR_SIZE, | ||
| 234 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 235 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 236 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID3); | ||
| 237 | + } else { | ||
| 238 | + // *** go = lo | ||
| 239 | + AscendC::DataCopy( | ||
| 240 | + goUbTensor, gInput, AscendC::DataCopyParams(1, curRowNum * embedRound / HALF_BLOCK_SIZE, 0, 0)); | ||
| 241 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 242 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(EVENT_ID0); | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + if (isLastStackTile) { | ||
| 246 | + // *** gl_block = expand_to_block(gl), 存放于 tv | ||
| 247 | + AscendC::Brcb( | ||
| 248 | + tvUbTensor.ReinterpretCast<uint16_t>(), | ||
| 249 | + glUbTensor.ReinterpretCast<uint16_t>()[rowOffsetLoop], | ||
| 250 | + curRowNumRound / FLOAT_BLOCK_SIZE, | ||
| 251 | + AscendC::BrcbRepeatParams(1, 8)); | ||
| 252 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 253 | + // *** go = go / gl_block | ||
| 254 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 255 | + for (uint32_t vdiv_idx = 0; vdiv_idx < embed / HALF_VECTOR_SIZE; ++vdiv_idx) { | ||
| 256 | + AscendC::Div<half, false>( | ||
| 257 | + goUbTensor[vdiv_idx * HALF_VECTOR_SIZE], | ||
| 258 | + goUbTensor[vdiv_idx * HALF_VECTOR_SIZE], | ||
| 259 | + tvUbTensor, | ||
| 260 | + (uint64_t)0, | ||
| 261 | + curRowNum, | ||
| 262 | + AscendC::BinaryRepeatParams( | ||
| 263 | + 1, 1, 0, embedRound / HALF_BLOCK_SIZE, embedRound / HALF_BLOCK_SIZE, 1)); | ||
| 264 | + } | ||
| 265 | + if (embed % HALF_VECTOR_SIZE > 0) { | ||
| 266 | + SetMask(embed % HALF_VECTOR_SIZE); | ||
| 267 | + AscendC::Div<half, false>( | ||
| 268 | + goUbTensor[embed / HALF_VECTOR_SIZE * HALF_VECTOR_SIZE], | ||
| 269 | + goUbTensor[embed / HALF_VECTOR_SIZE * HALF_VECTOR_SIZE], | ||
| 270 | + tvUbTensor, | ||
| 271 | + (uint64_t)0, | ||
| 272 | + curRowNum, | ||
| 273 | + AscendC::BinaryRepeatParams( | ||
| 274 | + 1, 1, 0, embedRound / HALF_BLOCK_SIZE, embedRound / HALF_BLOCK_SIZE, 1)); | ||
| 275 | + AscendC::SetVectorMask<int8_t>((uint64_t)-1, (uint64_t)-1); | ||
| 276 | + } | ||
| 277 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 278 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID0); | ||
| 279 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID0); | ||
| 280 | + | ||
| 281 | + // ***move O to GM | ||
| 282 | + CopyOToGm( | ||
| 283 | + gOutput, proTokenIdx, proTokenNum, epiTokenNum, integralHeadNum, qSThisSubBlock, embed, oHiddenSize); | ||
| 284 | + if constexpr (LSE_MODE == LseMode::OUT_ONLY) { | ||
| 285 | + if (isLastRowLoop) { | ||
| 286 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 287 | + AscendC::Ln<half, false>( | ||
| 288 | + lse16_ubuf_tensor, | ||
| 289 | + glUbTensor, | ||
| 290 | + (uint64_t)0, | ||
| 291 | + CeilDiv(totalRowNum, HALF_VECTOR_SIZE), | ||
| 292 | + AscendC::UnaryRepeatParams(1, 1, 8, 8)); | ||
| 293 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 294 | + AscendC::Add<half, false>( | ||
| 295 | + lse16_ubuf_tensor, | ||
| 296 | + lse16_ubuf_tensor, | ||
| 297 | + gmUbTensor, | ||
| 298 | + (uint64_t)0, | ||
| 299 | + CeilDiv(totalRowNum, HALF_VECTOR_SIZE), | ||
| 300 | + AscendC::BinaryRepeatParams(1, 1, 1, 8, 8, 8)); | ||
| 301 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 302 | + AscendC::Cast<float, half, false>( | ||
| 303 | + lse32_ubuf_tensor, | ||
| 304 | + lse16_ubuf_tensor, | ||
| 305 | + AscendC::RoundMode::CAST_NONE, | ||
| 306 | + (uint64_t)0, | ||
| 307 | + CeilDiv(totalRowNum, FLOAT_VECTOR_SIZE), | ||
| 308 | + AscendC::UnaryRepeatParams(1, 1, 8, 4)); | ||
| 309 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 310 | + | ||
| 311 | + // *** lse_block = expand_to_block(lse), 存放于 tv | ||
| 312 | + AscendC::Brcb( | ||
| 313 | + tvUbTensor32.ReinterpretCast<uint32_t>(), | ||
| 314 | + lse32_ubuf_tensor.ReinterpretCast<uint32_t>(), | ||
| 315 | + CeilDiv(totalRowNum, FLOAT_BLOCK_SIZE), | ||
| 316 | + AscendC::BrcbRepeatParams(1, 8)); | ||
| 317 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 318 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID4); | ||
| 319 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID4); | ||
| 320 | + | ||
| 321 | + if (qNThisSubBlock == 0U) { | ||
| 322 | + AscendC::DataCopyPad( | ||
| 323 | + gLse, tvUbTensor32, | ||
| 324 | + AscendC::DataCopyExtParams( | ||
| 325 | + totalRowNum, sizeof(float), 0, (stride - 1) * sizeof(float), 0)); | ||
| 326 | + } else { | ||
| 327 | + for (uint32_t qNIdx = 0; qNIdx < qNThisSubBlock; qNIdx++) { | ||
| 328 | + AscendC::DataCopyPad( | ||
| 329 | + gLse[qNIdx], | ||
| 330 | + tvUbTensor32[qNIdx * qSBlockSize * FLOAT_BLOCK_SIZE], | ||
| 331 | + AscendC::DataCopyExtParams( | ||
| 332 | + qSBlockSize, sizeof(float), 0, (stride - 1) * sizeof(float), 0)); | ||
| 333 | + } | ||
| 334 | + } | ||
| 335 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 336 | + } | ||
| 337 | + } | ||
| 338 | + } else if (needRowLoop) { | ||
| 339 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID5); | ||
| 340 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(EVENT_ID5); | ||
| 341 | + AscendC::DataCopy( | ||
| 342 | + gUpdate, goUbTensor, AscendC::DataCopyParams(1, curRowNum * embedRound / HALF_BLOCK_SIZE, 0, 0)); | ||
| 343 | + } | ||
| 344 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID6); | ||
| 345 | + } | ||
| 346 | + | ||
| 347 | + __aicore__ inline | ||
| 348 | + void operator()( | ||
| 349 | + AscendC::GlobalTensor<ElementOutput> gOutput, | ||
| 350 | + AscendC::GlobalTensor<ElementInput> gInput, | ||
| 351 | + AscendC::GlobalTensor<ElementUpdate> gUpdate, | ||
| 352 | + AscendC::GlobalTensor<ElementLse> gLse, | ||
| 353 | + const LayoutOutput &layoutOutput, | ||
| 354 | + const LayoutInput &layoutInput, | ||
| 355 | + const LayoutUpdate &layoutUpdate, | ||
| 356 | + const LayoutLse &layoutLse, | ||
| 357 | + GemmCoord actualBlockShape, | ||
| 358 | + uint32_t qSBlockSize, uint32_t qNBlockSize, | ||
| 359 | + uint32_t isFirstStackTile, uint32_t isLastStackTile, uint32_t curStackTileMod) | ||
| 360 | + { | ||
| 361 | + uint32_t rowNum = actualBlockShape.m(); | ||
| 362 | + uint32_t embed = actualBlockShape.n(); | ||
| 363 | + uint32_t maxRowNumPerLoop = MAX_UB_O_ELEM_NUM / embed; | ||
| 364 | + uint32_t rowNumTile = RoundDown(maxRowNumPerLoop, HALF_BLOCK_SIZE); | ||
| 365 | + | ||
| 366 | + uint32_t subBlockIdx = AscendC::GetSubBlockIdx(); | ||
| 367 | + uint32_t subBlockNum = AscendC::GetSubBlockNum(); | ||
| 368 | + | ||
| 369 | + uint32_t qNSplitSubBlock = qNBlockSize / subBlockNum; | ||
| 370 | + uint32_t qNThisSubBlock = (qNBlockSize == 1U) ? 0 | ||
| 371 | + : (subBlockIdx == 1U) ? (qNBlockSize - qNSplitSubBlock) | ||
| 372 | + : qNSplitSubBlock; | ||
| 373 | + uint32_t inRowSplitSubBlock = | ||
| 374 | + (qNBlockSize == 1U) ? (qSBlockSize / subBlockNum) : (qSBlockSize * qNSplitSubBlock); | ||
| 375 | + uint32_t inRowActualThisSubBlock = (subBlockIdx == 1U) ? (rowNum - inRowSplitSubBlock) : inRowSplitSubBlock; | ||
| 376 | + uint32_t inRowOffsetThisSubBlock = subBlockIdx * inRowSplitSubBlock; | ||
| 377 | + uint32_t outRowOffsetThisSubBlock = (qNBlockSize == 1U) ? inRowOffsetThisSubBlock : 0; | ||
| 378 | + uint32_t outColOffsetThisSubBlock = (qNBlockSize == 1U) ? 0 : subBlockIdx * qNSplitSubBlock * embed; | ||
| 379 | + uint32_t qSThisSubBlock = (qNBlockSize == 1U) ? inRowActualThisSubBlock : qSBlockSize; | ||
| 380 | + int64_t outOffsetSubBlock = | ||
| 381 | + layoutOutput.GetOffset(MatrixCoord(outRowOffsetThisSubBlock, outColOffsetThisSubBlock)); | ||
| 382 | + | ||
| 383 | + uint32_t outLseRowOffsetThisSubBlock = (qNBlockSize == 1U) ? inRowOffsetThisSubBlock : 0; | ||
| 384 | + uint32_t outLseColOffsetThisSubBlock = (qNBlockSize == 1U) ? 0 : subBlockIdx * qNSplitSubBlock; | ||
| 385 | + int64_t offsetLse = layoutLse.GetOffset(MatrixCoord(outLseRowOffsetThisSubBlock, outLseColOffsetThisSubBlock)); | ||
| 386 | + auto gLseThisSubBlock = gLse[offsetLse]; | ||
| 387 | + | ||
| 388 | + if (inRowActualThisSubBlock > 0U) { | ||
| 389 | + uint32_t rowLoop = CeilDiv(inRowActualThisSubBlock, rowNumTile); | ||
| 390 | + uint32_t needRowLoop = (rowLoop > 1U) ? 1 : 0; | ||
| 391 | + | ||
| 392 | + // The rows of each cycle consist of multiple heads with several tokens. | ||
| 393 | + // There are several integral heads, one prologue head, one epilogue head. | ||
| 394 | + uint32_t proTokenIdx = 0; // the token idx of the start token of the prologue part | ||
| 395 | + uint32_t proTokenIdxPre = 0; // the token idx of the start token of the pre prologue part | ||
| 396 | + uint32_t proTokenNum = 0; // the token num of the prologue part | ||
| 397 | + uint32_t epiTokenNum = 0; // the token num of the epilogue part | ||
| 398 | + uint32_t integralHeadNum = 0; // the number of integral heads within a cycle | ||
| 399 | + uint32_t qSRemian = qSThisSubBlock; | ||
| 400 | + for (uint32_t rowLoopIdx = 0; rowLoopIdx < rowLoop; rowLoopIdx++) { | ||
| 401 | + uint32_t rowOffsetLoop = rowLoopIdx * rowNumTile; | ||
| 402 | + uint32_t rowOffsetCurLoop = inRowOffsetThisSubBlock + rowOffsetLoop; | ||
| 403 | + uint32_t rowActualCurLoop = | ||
| 404 | + (rowLoopIdx == (rowLoop - 1U)) ? inRowActualThisSubBlock - rowLoopIdx * rowNumTile : rowNumTile; | ||
| 405 | + | ||
| 406 | + int64_t offsetOutput = | ||
| 407 | + static_cast<int64_t>(rowLoopIdx * rowNumTile / qSThisSubBlock * embed) + outOffsetSubBlock; | ||
| 408 | + auto gOutputCurLoop = gOutput[offsetOutput]; | ||
| 409 | + auto layoutOutputCurLoop = layoutOutput; | ||
| 410 | + int64_t offsetInput = layoutInput.GetOffset(MatrixCoord(rowOffsetCurLoop, 0)); | ||
| 411 | + auto gInputCurLoop = gInput[offsetInput]; | ||
| 412 | + auto layoutInputCurLoop = layoutInput.GetTileLayout(MatrixCoord(rowActualCurLoop, embed)); | ||
| 413 | + | ||
| 414 | + int64_t offsetUpdate = layoutUpdate.GetOffset(MatrixCoord(rowOffsetCurLoop, 0)); | ||
| 415 | + auto gUpdateCurLoop = gUpdate[offsetUpdate]; | ||
| 416 | + auto layoutUpdateCurLoop = layoutUpdate.GetTileLayout(MatrixCoord(rowActualCurLoop, embed)); | ||
| 417 | + | ||
| 418 | + proTokenIdx = rowOffsetLoop % qSThisSubBlock; | ||
| 419 | + proTokenNum = AscendC::Std::min(rowActualCurLoop, (qSThisSubBlock - proTokenIdx)) % qSThisSubBlock; | ||
| 420 | + integralHeadNum = (rowActualCurLoop - proTokenNum) / qSThisSubBlock; | ||
| 421 | + epiTokenNum = rowActualCurLoop - proTokenNum - integralHeadNum * qSThisSubBlock; | ||
| 422 | + | ||
| 423 | + SubCoreCompute( | ||
| 424 | + gOutputCurLoop, | ||
| 425 | + gInputCurLoop, | ||
| 426 | + gUpdateCurLoop, | ||
| 427 | + gLseThisSubBlock, | ||
| 428 | + layoutOutputCurLoop, | ||
| 429 | + layoutInputCurLoop, | ||
| 430 | + layoutUpdateCurLoop, | ||
| 431 | + layoutLse, | ||
| 432 | + qNThisSubBlock, | ||
| 433 | + qSThisSubBlock, | ||
| 434 | + inRowActualThisSubBlock, | ||
| 435 | + isFirstStackTile, | ||
| 436 | + isLastStackTile, | ||
| 437 | + curStackTileMod, | ||
| 438 | + needRowLoop, | ||
| 439 | + (rowLoopIdx == rowLoop - 1U), | ||
| 440 | + rowOffsetLoop, | ||
| 441 | + proTokenIdx, | ||
| 442 | + proTokenNum, | ||
| 443 | + epiTokenNum, | ||
| 444 | + integralHeadNum); | ||
| 445 | + } | ||
| 446 | + } | ||
| 447 | + } | ||
| 448 | + | ||
| 449 | +private: | ||
| 450 | + AscendC::LocalTensor<half> loUbTensor; | ||
| 451 | + AscendC::LocalTensor<half> dmUbTensor; | ||
| 452 | + AscendC::LocalTensor<half> hmUbTensor; | ||
| 453 | + AscendC::LocalTensor<half> glUbTensor; | ||
| 454 | + AscendC::LocalTensor<half> tvUbTensor; | ||
| 455 | + AscendC::LocalTensor<float> tvUbTensor32; | ||
| 456 | + AscendC::LocalTensor<ElementOutput> goUbTensor; | ||
| 457 | + AscendC::LocalTensor<half> gmUbTensor; | ||
| 458 | + AscendC::LocalTensor<half> lse16_ubuf_tensor; | ||
| 459 | + AscendC::LocalTensor<float> lse32_ubuf_tensor; | ||
| 460 | +}; | ||
| 461 | +} | ||
| 462 | + | ||
| 463 | + | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace NpuArch::Epilogue | ||
| 18 | +{ | ||
| 19 | + | ||
| 20 | +enum class LseMode {NONE = 0, OUT_ONLY = 1}; | ||
| 21 | +// For AtlasA2, FA Infer online Softmax | ||
| 22 | +template <LseMode LSE_MODE_, typename SM_DTYPE_> | ||
| 23 | +struct EpilogueAtlasA2OnlineSoftmax { | ||
| 24 | + using ArchTag = Arch::AtlasA2; | ||
| 25 | + using IntermPrec = SM_DTYPE_; | ||
| 26 | + static constexpr LseMode LSE_MODE = LSE_MODE_; | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +// For AtlasA2, FA Infer RescaleO | ||
| 30 | +template <LseMode LSE_MODE_, typename SM_DTYPE_> | ||
| 31 | +struct EpilogueAtlasA2RescaleO { | ||
| 32 | + using ArchTag = Arch::AtlasA2; | ||
| 33 | + using IntermPrec = SM_DTYPE_; | ||
| 34 | + static constexpr LseMode LSE_MODE = LSE_MODE_; | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +// For AtlasA5 | ||
| 38 | +struct EpilogueBsaMask2Idx { | ||
| 39 | + static constexpr uint32_t IO_STAGES = 2; | ||
| 40 | + using ArchTag = Arch::AtlasA5; | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +struct EpilogueOnlineSoftmaxBsa { | ||
| 44 | + using ArchTag = Arch::AtlasA5; | ||
| 45 | +}; | ||
| 46 | + | ||
| 47 | +struct EpilogueAtlasA5BsaRescaleO { | ||
| 48 | + using ArchTag = Arch::AtlasA5; | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +} // namespace NpuArch::Epilogue | ||
| 52 | + | ||
| 53 | + | ||
| @@ -0,0 +1,188 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::Epilogue::Tile | ||
| 20 | +{ | ||
| 21 | + | ||
| 22 | +template < | ||
| 23 | + class ArchTag, | ||
| 24 | + class GmType | ||
| 25 | +> | ||
| 26 | +struct CopyGm2Ub { | ||
| 27 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy gm to ub, can not find the specialization."); | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | +template <typename Element> | ||
| 31 | +struct CopyGm2Ub<Arch::AtlasA2, Gemm::GemmType<Element, layout::RowMajor>> { | ||
| 32 | + using LayoutSrc = layout::RowMajor; | ||
| 33 | + using LayoutDst = layout::RowMajor; | ||
| 34 | + | ||
| 35 | + static constexpr uint32_t ELE_NUM_PER_BLK = static_cast<uint32_t>(BYTE_PER_BLK) / static_cast<uint32_t>(sizeof(Element)); | ||
| 36 | + | ||
| 37 | + __aicore__ inline | ||
| 38 | + CopyGm2Ub() = default; | ||
| 39 | + | ||
| 40 | + __aicore__ inline | ||
| 41 | + void operator()( | ||
| 42 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 43 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 44 | + layout::RowMajor const &layoutDst, | ||
| 45 | + layout::RowMajor const &layoutSrc) | ||
| 46 | + { | ||
| 47 | + AscendC::DataCopyExtParams dataCopyParams( | ||
| 48 | + layoutSrc.shape(0), | ||
| 49 | + layoutSrc.shape(1) * sizeof(Element), | ||
| 50 | + (layoutSrc.stride(0) - layoutSrc.shape(1)) * sizeof(Element), | ||
| 51 | + (layoutDst.stride(0) - layoutDst.shape(1)) / ELE_NUM_PER_BLK, | ||
| 52 | + 0 | ||
| 53 | + ); | ||
| 54 | + AscendC::DataCopyPadExtParams<Element> padParams(false, 0, 0, 0); | ||
| 55 | + AscendC::DataCopyPad(dstTensor, srcTensor, dataCopyParams, padParams); | ||
| 56 | + }; | ||
| 57 | +}; | ||
| 58 | + | ||
| 59 | +template <typename Element> | ||
| 60 | +struct CopyGm2Ub<Arch::AtlasA2, Gemm::GemmType<Element, layout::VectorLayout>> { | ||
| 61 | + using LayoutSrc = layout::VectorLayout; | ||
| 62 | + using LayoutDst = layout::VectorLayout; | ||
| 63 | + | ||
| 64 | + static constexpr uint32_t ELE_NUM_PER_BLK = static_cast<uint32_t>(BYTE_PER_BLK) / static_cast<uint32_t>(sizeof(Element)); | ||
| 65 | + | ||
| 66 | + __aicore__ inline | ||
| 67 | + CopyGm2Ub() = default; | ||
| 68 | + | ||
| 69 | + __aicore__ inline | ||
| 70 | + void operator()( | ||
| 71 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 72 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 73 | + layout::VectorLayout const &layoutDst, | ||
| 74 | + layout::VectorLayout const &layoutSrc) | ||
| 75 | + { | ||
| 76 | + AscendC::DataCopyExtParams dataCopyParams( | ||
| 77 | + 1, | ||
| 78 | + layoutSrc.shape(0) * sizeof(Element), | ||
| 79 | + 0, | ||
| 80 | + 0, | ||
| 81 | + 0 | ||
| 82 | + ); | ||
| 83 | + AscendC::DataCopyPadExtParams<Element> padParams(false, 0, 0, 0); | ||
| 84 | + AscendC::DataCopyPad(dstTensor, srcTensor, dataCopyParams, padParams); | ||
| 85 | + }; | ||
| 86 | +}; | ||
| 87 | + | ||
| 88 | +/// @brief This copy instruction used to copy per token scale from GM to UB. | ||
| 89 | +/// Copy the scale of shape (m,1) on GM to the first column of shape (m,n) on UB, | ||
| 90 | +/// and pad the first block of each row (i.e. pad to shape (m,8) when element type is float). | ||
| 91 | +/// @tparam ArchTag: Architecture tag. | ||
| 92 | +/// @tparam GmType: Type of data on GM. | ||
| 93 | +template < | ||
| 94 | + class ArchTag, | ||
| 95 | + class GmType | ||
| 96 | +> | ||
| 97 | +struct CopyPerTokenScale2Ub { | ||
| 98 | + static_assert(std::is_same_v<typename GmType::Layout, layout::ColumnMajor>, | ||
| 99 | + "Unsupported layout for CopyPerTokenScale2Ub."); | ||
| 100 | + | ||
| 101 | + using Element = typename GmType::Element; | ||
| 102 | + using LayoutSrc = typename GmType::Layout; | ||
| 103 | + using LayoutDst = layout::RowMajor; | ||
| 104 | + | ||
| 105 | + static constexpr uint32_t ELE_NUM_PER_BLK = static_cast<uint32_t>(BYTE_PER_BLK) / static_cast<uint32_t>(sizeof(Element)); | ||
| 106 | + | ||
| 107 | + __aicore__ inline | ||
| 108 | + CopyPerTokenScale2Ub() = default; | ||
| 109 | + | ||
| 110 | + __aicore__ inline | ||
| 111 | + void operator()( | ||
| 112 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 113 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 114 | + LayoutDst const &layoutDst, | ||
| 115 | + LayoutSrc const &layoutSrc) | ||
| 116 | + { | ||
| 117 | + AscendC::DataCopyExtParams dataCopyParams; | ||
| 118 | + AscendC::DataCopyPadExtParams<Element> padParams; | ||
| 119 | + | ||
| 120 | + dataCopyParams.blockCount = layoutSrc.shape(0); | ||
| 121 | + dataCopyParams.blockLen = layoutSrc.shape(1) * sizeof(Element); // per token scale has only one column | ||
| 122 | + dataCopyParams.srcStride = 0; | ||
| 123 | + dataCopyParams.dstStride = (layoutDst.stride(0) - layoutDst.shape(1)) / ELE_NUM_PER_BLK; | ||
| 124 | + // Pad the data to the complete block | ||
| 125 | + padParams.isPad = true; | ||
| 126 | + padParams.leftPadding = 0; | ||
| 127 | + padParams.rightPadding = 0; | ||
| 128 | + | ||
| 129 | + AscendC::DataCopyPad(dstTensor, srcTensor, dataCopyParams, padParams); | ||
| 130 | + } | ||
| 131 | +}; | ||
| 132 | + | ||
| 133 | +template < | ||
| 134 | + class ArchTag, | ||
| 135 | + class GmType | ||
| 136 | +> | ||
| 137 | +struct CopyGm2UbAligned { | ||
| 138 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy gm to ub aligned, can not find the specialization."); | ||
| 139 | +}; | ||
| 140 | + | ||
| 141 | +template <typename Element> | ||
| 142 | +struct CopyGm2UbAligned<Arch::AtlasA2, Gemm::GemmType<Element, layout::RowMajor>> { | ||
| 143 | + using LayoutSrc = layout::RowMajor; | ||
| 144 | + using LayoutDst = layout::RowMajor; | ||
| 145 | + | ||
| 146 | + static constexpr uint32_t ELE_NUM_PER_BLK = static_cast<uint32_t>(BYTE_PER_BLK) / static_cast<uint32_t>(sizeof(Element)); | ||
| 147 | + static constexpr uint32_t BLOCK_LEN_LIMIT = 65536; | ||
| 148 | + static constexpr uint32_t MAX_REPEAT = 4095; | ||
| 149 | + static constexpr uint32_t STRIDE_LIMIT = 65536; | ||
| 150 | + | ||
| 151 | + __aicore__ inline | ||
| 152 | + CopyGm2UbAligned() = default; | ||
| 153 | + | ||
| 154 | + __aicore__ inline | ||
| 155 | + void operator()( | ||
| 156 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 157 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 158 | + layout::RowMajor const &layoutDst, | ||
| 159 | + layout::RowMajor const &layoutSrc) | ||
| 160 | + { | ||
| 161 | + uint32_t rows = layoutSrc.shape(0); | ||
| 162 | + uint32_t cols = layoutSrc.shape(1); | ||
| 163 | + uint32_t srcStride = (layoutSrc.stride(0) - layoutSrc.shape(1)) / ELE_NUM_PER_BLK; | ||
| 164 | + uint32_t dstStride = (layoutDst.stride(0) - layoutDst.shape(1)) / ELE_NUM_PER_BLK; | ||
| 165 | + | ||
| 166 | + if ((layoutSrc.shape(1) == layoutSrc.stride(0)) && (layoutDst.shape(1) == layoutDst.stride(0))) { | ||
| 167 | + DataCopy(dstTensor, srcTensor, rows * cols); | ||
| 168 | + } else if (srcStride < STRIDE_LIMIT && dstStride < STRIDE_LIMIT && (cols / ELE_NUM_PER_BLK) < BLOCK_LEN_LIMIT) { | ||
| 169 | + uint32_t rLoops = CeilDiv(rows, MAX_REPEAT); | ||
| 170 | + for (uint32_t i = 0; i < rLoops; ++i) { | ||
| 171 | + uint32_t rActual = (i < rLoops - 1) ? MAX_REPEAT : rows - i * MAX_REPEAT; | ||
| 172 | + AscendC::DataCopyParams dataCopyParams( | ||
| 173 | + rActual, cols / ELE_NUM_PER_BLK, srcStride, dstStride | ||
| 174 | + ); | ||
| 175 | + DataCopy(dstTensor[i * MAX_REPEAT * layoutDst.stride(0)], | ||
| 176 | + srcTensor[i * MAX_REPEAT * layoutSrc.stride(0)], dataCopyParams); | ||
| 177 | + } | ||
| 178 | + } else { | ||
| 179 | + for (uint32_t i = 0; i < rows; ++i) { | ||
| 180 | + DataCopy(dstTensor[i * layoutDst.stride(0)], srcTensor[i * layoutSrc.stride(0)], cols); | ||
| 181 | + } | ||
| 182 | + } | ||
| 183 | + }; | ||
| 184 | +}; | ||
| 185 | + | ||
| 186 | +} // NpuArch::Epilogue::Tile | ||
| 187 | + | ||
| 188 | + | ||
| @@ -0,0 +1,113 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::Epilogue::Tile | ||
| 20 | +{ | ||
| 21 | + | ||
| 22 | +template < | ||
| 23 | + class ArchTag, | ||
| 24 | + class TensorSrc, | ||
| 25 | + class TensorDst, | ||
| 26 | + class Enable = void | ||
| 27 | +> | ||
| 28 | +struct CopyGm2UbTla { | ||
| 29 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported CopyGm2UbTla, can not find the specialization."); | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +/// Partial specialization for AtlasA2, RowMajor in and RowMajor out. | ||
| 33 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 34 | +struct CopyGm2UbTla<Arch::AtlasA2, | ||
| 35 | + tla::Tensor<AscendC::GlobalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::GM>, | ||
| 36 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::VECCALC>, | ||
| 37 | + std::enable_if_t<tla::detail::isRowMajor<LayoutSrc>::value && | ||
| 38 | + tla::detail::isRowMajor<LayoutDst>::value>> { | ||
| 39 | + static constexpr uint32_t ELE_NUM_PER_BLK = BYTE_PER_BLK / sizeof(ElementSrc); | ||
| 40 | + | ||
| 41 | + // Methods | ||
| 42 | + | ||
| 43 | + __aicore__ inline | ||
| 44 | + CopyGm2UbTla() = default; | ||
| 45 | + | ||
| 46 | + template <class TensorDst, class TensorSrc> | ||
| 47 | + __aicore__ inline | ||
| 48 | + void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 49 | + { | ||
| 50 | + static_assert(tla::detail::isRowMajor<typename TensorSrc::Layout>::value && | ||
| 51 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && | ||
| 52 | + TensorSrc::position == AscendC::TPosition::GM && | ||
| 53 | + TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 54 | + "The input parameters do not match. TensorSrc must be GM and RowMajor, " | ||
| 55 | + "while TensorDst must be UB and RowMajor"); | ||
| 56 | + | ||
| 57 | + AscendC::DataCopyExtParams dataCopyParams( | ||
| 58 | + tla::get<0>(srcTensor.shape()), | ||
| 59 | + tla::get<1>(srcTensor.shape()) * sizeof(ElementSrc), | ||
| 60 | + (tla::get<0>(srcTensor.stride()) - tla::get<1>(srcTensor.shape())) * sizeof(ElementSrc), | ||
| 61 | + (tla::get<0>(dstTensor.stride()) - tla::get<1>(dstTensor.shape())) / ELE_NUM_PER_BLK, | ||
| 62 | + 0 | ||
| 63 | + ); | ||
| 64 | + AscendC::DataCopyPadExtParams<ElementSrc> padParams(false, 0, 0, 0); | ||
| 65 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 66 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 67 | + AscendC::DataCopyPad(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], dataCopyParams, padParams); | ||
| 68 | + }; | ||
| 69 | +}; | ||
| 70 | + | ||
| 71 | +/// Partial specialization for AtlasA5, RowMajor in and RowMajor out. | ||
| 72 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 73 | +struct CopyGm2UbTla<Arch::AtlasA5, | ||
| 74 | + tla::Tensor<AscendC::GlobalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::GM>, | ||
| 75 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::VECCALC>, | ||
| 76 | + std::enable_if_t<tla::detail::isRowMajor<LayoutSrc>::value && | ||
| 77 | + tla::detail::isRowMajor<LayoutDst>::value>> { | ||
| 78 | + static constexpr uint32_t ELE_NUM_PER_BLK = BYTE_PER_BLK / sizeof(ElementSrc); | ||
| 79 | + | ||
| 80 | + // Methods | ||
| 81 | + | ||
| 82 | + __aicore__ inline | ||
| 83 | + CopyGm2UbTla() = default; | ||
| 84 | + | ||
| 85 | + template <class TensorDst, class TensorSrc> | ||
| 86 | + __aicore__ inline | ||
| 87 | + void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 88 | + { | ||
| 89 | + static_assert(tla::detail::isRowMajor<typename TensorSrc::Layout>::value && | ||
| 90 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && | ||
| 91 | + TensorSrc::position == AscendC::TPosition::GM && | ||
| 92 | + TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 93 | + "The input parameters do not match. TensorSrc must be GM and RowMajor, " | ||
| 94 | + "while TensorDst must be UB and RowMajor"); | ||
| 95 | + | ||
| 96 | + AscendC::DataCopyExtParams dataCopyParams( | ||
| 97 | + tla::get<0>(srcTensor.shape()), | ||
| 98 | + tla::get<1>(srcTensor.shape()) * sizeof(ElementSrc), | ||
| 99 | + (tla::get<0>(srcTensor.stride()) - tla::get<1>(srcTensor.shape())) * sizeof(ElementSrc), | ||
| 100 | + (tla::get<0>(dstTensor.stride()) - tla::get<1>(dstTensor.shape())) / ELE_NUM_PER_BLK, | ||
| 101 | + 0 | ||
| 102 | + ); | ||
| 103 | + AscendC::DataCopyPadExtParams<ElementSrc> padParams(false, 0, 0, 0); | ||
| 104 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 105 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 106 | + AscendC::DataCopyPad(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], dataCopyParams, padParams); | ||
| 107 | + }; | ||
| 108 | +}; | ||
| 109 | + | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | + | ||
| 113 | + | ||
| @@ -0,0 +1,144 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::Epilogue::Tile | ||
| 20 | +{ | ||
| 21 | + | ||
| 22 | +template < | ||
| 23 | + class ArchTag, | ||
| 24 | + class GmType | ||
| 25 | +> | ||
| 26 | +struct CopyUb2Gm { | ||
| 27 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy ub to gm, can not find the specialization."); | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | +template <typename Element> | ||
| 31 | +struct CopyUb2Gm<Arch::AtlasA2, Gemm::GemmType<Element, layout::RowMajor>> { | ||
| 32 | + using LayoutDst = layout::RowMajor; | ||
| 33 | + using LayoutSrc = layout::RowMajor; | ||
| 34 | + | ||
| 35 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 36 | + | ||
| 37 | + __aicore__ inline | ||
| 38 | + CopyUb2Gm() = default; | ||
| 39 | + | ||
| 40 | + __aicore__ inline | ||
| 41 | + void operator()( | ||
| 42 | + AscendC::GlobalTensor<Element> const &dstTensor, | ||
| 43 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 44 | + layout::RowMajor const &layoutDst, | ||
| 45 | + layout::RowMajor const &layoutSrc) | ||
| 46 | + { | ||
| 47 | + AscendC::DataCopyExtParams dataCopyParams( | ||
| 48 | + layoutDst.shape(0), | ||
| 49 | + layoutDst.shape(1) * sizeof(Element), | ||
| 50 | + (layoutSrc.stride(0) - layoutSrc.shape(1)) / ELE_NUM_PER_C0, | ||
| 51 | + (layoutDst.stride(0) - layoutDst.shape(1)) * sizeof(Element), | ||
| 52 | + 0 | ||
| 53 | + ); | ||
| 54 | + AscendC::DataCopyPad(dstTensor, srcTensor, dataCopyParams); | ||
| 55 | + } | ||
| 56 | +}; | ||
| 57 | + | ||
| 58 | + | ||
| 59 | +// new add vectorlayout version | ||
| 60 | +template <typename Element> | ||
| 61 | +struct CopyUb2Gm<Arch::AtlasA2, Gemm::GemmType<Element, layout::VectorLayout>> { | ||
| 62 | + using LayoutSrc = layout::VectorLayout; | ||
| 63 | + using LayoutDst = layout::VectorLayout; | ||
| 64 | + | ||
| 65 | + static constexpr uint32_t ELE_NUM_PER_BLK = BYTE_PER_BLK / sizeof(Element); | ||
| 66 | + | ||
| 67 | + __aicore__ inline | ||
| 68 | + CopyUb2Gm() = default; | ||
| 69 | + | ||
| 70 | + __aicore__ inline | ||
| 71 | + void operator()( | ||
| 72 | + AscendC::GlobalTensor<Element> const &dstTensor, | ||
| 73 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 74 | + layout::VectorLayout const &layoutDst, | ||
| 75 | + layout::VectorLayout const &layoutSrc) | ||
| 76 | + { | ||
| 77 | + AscendC::DataCopyExtParams dataCopyParams( | ||
| 78 | + 1, | ||
| 79 | + layoutDst.shape(0) * sizeof(Element), | ||
| 80 | + 0, | ||
| 81 | + 0, | ||
| 82 | + 0 | ||
| 83 | + ); | ||
| 84 | + AscendC::DataCopyPad(dstTensor, srcTensor, dataCopyParams); | ||
| 85 | + }; | ||
| 86 | +}; | ||
| 87 | + | ||
| 88 | + | ||
| 89 | +template < | ||
| 90 | + class ArchTag, | ||
| 91 | + class GmType | ||
| 92 | +> | ||
| 93 | +struct CopyUb2GmAligned { | ||
| 94 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy ub to gm aligned, can not find the specialization."); | ||
| 95 | +}; | ||
| 96 | + | ||
| 97 | +template <typename Element> | ||
| 98 | +struct CopyUb2GmAligned<Arch::AtlasA2, Gemm::GemmType<Element, layout::RowMajor>> { | ||
| 99 | + using LayoutSrc = layout::RowMajor; | ||
| 100 | + using LayoutDst = layout::RowMajor; | ||
| 101 | + | ||
| 102 | + static constexpr uint32_t ELE_NUM_PER_BLK = BYTE_PER_BLK / sizeof(Element); | ||
| 103 | + static constexpr uint32_t BLOCK_LEN_LIMIT = 65536; | ||
| 104 | + static constexpr uint32_t MAX_REPEAT = 4095; | ||
| 105 | + static constexpr uint32_t STRIDE_LIMIT = 65536; | ||
| 106 | + | ||
| 107 | + __aicore__ inline | ||
| 108 | + CopyUb2GmAligned() = default; | ||
| 109 | + | ||
| 110 | + __aicore__ inline | ||
| 111 | + void operator()( | ||
| 112 | + AscendC::GlobalTensor<Element> const &dstTensor, | ||
| 113 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 114 | + layout::RowMajor const &layoutDst, | ||
| 115 | + layout::RowMajor const &layoutSrc) | ||
| 116 | + { | ||
| 117 | + uint32_t rows = layoutDst.shape(0); | ||
| 118 | + uint32_t cols = layoutDst.shape(1); | ||
| 119 | + uint32_t srcStride = (layoutSrc.stride(0) - layoutSrc.shape(1)) / ELE_NUM_PER_BLK; | ||
| 120 | + uint32_t dstStride = (layoutDst.stride(0) - layoutDst.shape(1)) / ELE_NUM_PER_BLK; | ||
| 121 | + | ||
| 122 | + if ((layoutSrc.shape(1) == layoutSrc.stride(0)) && (layoutDst.shape(1) == layoutDst.stride(0))) { | ||
| 123 | + DataCopy(dstTensor, srcTensor, rows * cols); | ||
| 124 | + } else if (srcStride < STRIDE_LIMIT && dstStride < STRIDE_LIMIT && (cols / ELE_NUM_PER_BLK) < BLOCK_LEN_LIMIT) { | ||
| 125 | + uint32_t rLoops = CeilDiv(rows, MAX_REPEAT); | ||
| 126 | + for (uint32_t i = 0; i < rLoops; ++i) { | ||
| 127 | + uint32_t rActual = (i < rLoops - 1) ? MAX_REPEAT : rows - i * MAX_REPEAT; | ||
| 128 | + AscendC::DataCopyParams dataCopyParams( | ||
| 129 | + rActual, cols / ELE_NUM_PER_BLK, srcStride, dstStride | ||
| 130 | + ); | ||
| 131 | + DataCopy(dstTensor[i * MAX_REPEAT * layoutDst.stride(0)], | ||
| 132 | + srcTensor[i * MAX_REPEAT * layoutSrc.stride(0)], dataCopyParams); | ||
| 133 | + } | ||
| 134 | + } else { | ||
| 135 | + for (uint32_t i = 0; i < rows; ++i) { | ||
| 136 | + DataCopy(dstTensor[i * layoutDst.stride(0)], srcTensor[i * layoutSrc.stride(0)], cols); | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + }; | ||
| 140 | +}; | ||
| 141 | + | ||
| 142 | +} // NpuArch::Epilogue::Tile | ||
| 143 | + | ||
| 144 | + | ||
| @@ -0,0 +1,110 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::Epilogue::Tile { | ||
| 20 | + | ||
| 21 | +template < | ||
| 22 | + class ArchTag, | ||
| 23 | + class TensorSrc, | ||
| 24 | + class TensorDst, | ||
| 25 | + class Enable = void | ||
| 26 | +> | ||
| 27 | +struct CopyUb2GmTla { | ||
| 28 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported CopyUb2GmTla, can not find the specialization."); | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +/// Partial specialization for AtlasA2, RowMajor in and RowMajor out. | ||
| 32 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 33 | +struct CopyUb2GmTla<Arch::AtlasA2, | ||
| 34 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::VECCALC>, | ||
| 35 | + tla::Tensor<AscendC::GlobalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::GM>, | ||
| 36 | + std::enable_if_t<tla::detail::isRowMajor<LayoutSrc>::value && | ||
| 37 | + tla::detail::isRowMajor<LayoutDst>::value>> { | ||
| 38 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 39 | + | ||
| 40 | + // Methods | ||
| 41 | + | ||
| 42 | + __aicore__ inline | ||
| 43 | + CopyUb2GmTla() = default; | ||
| 44 | + | ||
| 45 | + template <class TensorDst, class TensorSrc> | ||
| 46 | + __aicore__ inline | ||
| 47 | + void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 48 | + { | ||
| 49 | + static_assert(tla::detail::isRowMajor<typename TensorSrc::Layout>::value && | ||
| 50 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && | ||
| 51 | + TensorSrc::position == AscendC::TPosition::VECCALC && | ||
| 52 | + TensorDst::position == AscendC::TPosition::GM, | ||
| 53 | + "The input parameters do not match. TensorSrc must be UB and RowMajor, " | ||
| 54 | + "while TensorDst must be GM and RowMajor"); | ||
| 55 | + | ||
| 56 | + AscendC::DataCopyExtParams dataCopyParams( | ||
| 57 | + tla::get<0>(dstTensor.shape()), | ||
| 58 | + tla::get<1>(dstTensor.shape()) * sizeof(ElementSrc), | ||
| 59 | + (tla::get<0>(srcTensor.stride()) - tla::get<1>(srcTensor.shape())) / ELE_NUM_PER_C0, | ||
| 60 | + (tla::get<0>(dstTensor.stride()) - tla::get<1>(dstTensor.shape())) * sizeof(ElementSrc), | ||
| 61 | + 0 | ||
| 62 | + ); | ||
| 63 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 64 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 65 | + AscendC::DataCopyPad(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], dataCopyParams); | ||
| 66 | + }; | ||
| 67 | +}; | ||
| 68 | + | ||
| 69 | +/// Partial specialization for AtlasA5, RowMajor in and RowMajor out. | ||
| 70 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 71 | +struct CopyUb2GmTla<Arch::AtlasA5, | ||
| 72 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::VECCALC>, | ||
| 73 | + tla::Tensor<AscendC::GlobalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::GM>, | ||
| 74 | + std::enable_if_t<tla::detail::isRowMajor<LayoutSrc>::value && | ||
| 75 | + tla::detail::isRowMajor<LayoutDst>::value>> { | ||
| 76 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 77 | + | ||
| 78 | + // Methods | ||
| 79 | + | ||
| 80 | + __aicore__ inline | ||
| 81 | + CopyUb2GmTla() = default; | ||
| 82 | + | ||
| 83 | + template <class TensorDst, class TensorSrc> | ||
| 84 | + __aicore__ inline | ||
| 85 | + void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 86 | + { | ||
| 87 | + static_assert(tla::detail::isRowMajor<typename TensorSrc::Layout>::value && | ||
| 88 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && | ||
| 89 | + TensorSrc::position == AscendC::TPosition::VECCALC && | ||
| 90 | + TensorDst::position == AscendC::TPosition::GM, | ||
| 91 | + "The input parameters do not match. TensorSrc must be UB and RowMajor, " | ||
| 92 | + "while TensorDst must be GM and RowMajor"); | ||
| 93 | + | ||
| 94 | + AscendC::DataCopyExtParams dataCopyParams( | ||
| 95 | + tla::get<0>(dstTensor.shape()), | ||
| 96 | + tla::get<1>(dstTensor.shape()) * sizeof(ElementSrc), | ||
| 97 | + (tla::get<0>(srcTensor.stride()) - tla::get<1>(srcTensor.shape())) / ELE_NUM_PER_C0, | ||
| 98 | + (tla::get<0>(dstTensor.stride()) - tla::get<1>(dstTensor.shape())) * sizeof(ElementSrc), | ||
| 99 | + 0 | ||
| 100 | + ); | ||
| 101 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 102 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 103 | + AscendC::DataCopyPad(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], dataCopyParams); | ||
| 104 | + }; | ||
| 105 | +}; | ||
| 106 | + | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | + | ||
| 110 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/epilogue/tile_common/tile_copy.hpp+130-0
| @@ -0,0 +1,130 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +namespace NpuArch::Epilogue::Tile | ||
| 24 | +{ | ||
| 25 | + | ||
| 26 | +template < | ||
| 27 | + /// Tag indicating architecture | ||
| 28 | + class ArchTag, | ||
| 29 | + class... Args | ||
| 30 | +> | ||
| 31 | +struct TileCopy { | ||
| 32 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported tile_common copy, can not find the specialization."); | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +template < | ||
| 36 | + class ArchTag, | ||
| 37 | + /// GemmType for C matrix operand | ||
| 38 | + class CType, | ||
| 39 | + /// GemmType for X matrix operand | ||
| 40 | + class XType, | ||
| 41 | + /// GemmType for D matrix operand | ||
| 42 | + class DType | ||
| 43 | +> | ||
| 44 | +struct TileCopy<ArchTag, CType, XType, DType> { | ||
| 45 | + using ElementC = typename CType::Element; | ||
| 46 | + using ElementX = typename XType::Element; | ||
| 47 | + using ElementD = typename DType::Element; | ||
| 48 | + | ||
| 49 | + using CopyGmToUbC = CopyGm2Ub<ArchTag, CType>; | ||
| 50 | + using CopyGmToUbX = CopyGm2Ub<ArchTag, XType>; | ||
| 51 | + using CopyUbToGmD = CopyUb2Gm<ArchTag, DType>; | ||
| 52 | +}; | ||
| 53 | + | ||
| 54 | +template < | ||
| 55 | + class ArchTag, | ||
| 56 | + class CType, | ||
| 57 | + class XType, | ||
| 58 | + class YType, | ||
| 59 | + class DType | ||
| 60 | +> | ||
| 61 | +struct TileCopy<ArchTag, CType, XType, YType, DType> { | ||
| 62 | + using ElementC = typename CType::Element; | ||
| 63 | + using ElementX = typename XType::Element; | ||
| 64 | + using ElementY = typename YType::Element; | ||
| 65 | + using ElementD = typename DType::Element; | ||
| 66 | + | ||
| 67 | + using CopyGmToUbC = CopyGm2Ub<ArchTag, CType>; | ||
| 68 | + using CopyGmToUbX = CopyGm2Ub<ArchTag, XType>; | ||
| 69 | + using CopyGmToUbY = CopyGm2Ub<ArchTag, YType>; | ||
| 70 | + using CopyUbToGmD = CopyUb2Gm<ArchTag, DType>; | ||
| 71 | +}; | ||
| 72 | + | ||
| 73 | +template < | ||
| 74 | + class ArchTag, | ||
| 75 | + class CType, | ||
| 76 | + class XType, | ||
| 77 | + class YType, | ||
| 78 | + class DType | ||
| 79 | +> | ||
| 80 | +struct TileCopyBf16 { | ||
| 81 | + using ElementC = typename CType::Element; | ||
| 82 | + using ElementX = bfloat16_t; | ||
| 83 | + using ElementY = bfloat16_t; | ||
| 84 | + using ElementD = bfloat16_t; | ||
| 85 | + | ||
| 86 | + using CopyGmToUbC = CopyGm2Ub<ArchTag, CType>; | ||
| 87 | + using CopyGmToUbX = CopyGm2Ub<ArchTag, Gemm::GemmType<bfloat16_t, typename XType::Layout>>; | ||
| 88 | + using CopyGmToUbY = CopyGm2Ub<ArchTag, Gemm::GemmType<bfloat16_t, typename YType::Layout>>; | ||
| 89 | + using CopyUbToGmD = CopyUb2Gm<ArchTag, Gemm::GemmType<bfloat16_t, typename DType::Layout>>; | ||
| 90 | +}; | ||
| 91 | + | ||
| 92 | +template < | ||
| 93 | + class ArchTag, | ||
| 94 | + class CType, | ||
| 95 | + class ScaleType, | ||
| 96 | + class PerTokenScaleType, | ||
| 97 | + class DType | ||
| 98 | +> | ||
| 99 | +struct TileCopyPerTokenDequant { | ||
| 100 | + using ElementC = typename CType::Element; | ||
| 101 | + using ElementScale = typename ScaleType::Element; | ||
| 102 | + using ElementPerTokenScale = typename PerTokenScaleType::Element; | ||
| 103 | + using ElementD = typename DType::Element; | ||
| 104 | + | ||
| 105 | + using CopyGmToUbC = CopyGm2Ub<ArchTag, CType>; | ||
| 106 | + using CopyGmToUbScale = CopyGm2Ub<ArchTag, ScaleType>; | ||
| 107 | + using CopyGmToUbPerTokenScale = CopyPerTokenScale2Ub<ArchTag, PerTokenScaleType>; | ||
| 108 | + using CopyUbToGmD = CopyUb2Gm<ArchTag, DType>; | ||
| 109 | +}; | ||
| 110 | + | ||
| 111 | +template < | ||
| 112 | + class ArchTag, | ||
| 113 | + class ElementO_, | ||
| 114 | + class LayoutTagO_, | ||
| 115 | + class LayoutTagOTmp_ | ||
| 116 | +> | ||
| 117 | +struct TileCopyRescaleO{ | ||
| 118 | + using ElementO = ElementO_; | ||
| 119 | + using LayoutTagO = LayoutTagO_; | ||
| 120 | + using LayoutTagOTmp = LayoutTagOTmp_; | ||
| 121 | + using LayoutO = detail::TagToLayout_t<ElementO, LayoutTagO>; | ||
| 122 | + | ||
| 123 | + using TensorUbO = tla::Tensor<AscendC::LocalTensor<ElementO>, LayoutO, tla::Coord<tla::_0, tla::_0>, AscendC::TPosition::VECCALC>; | ||
| 124 | + using TensorGmO = tla::Tensor<AscendC::GlobalTensor<ElementO>, LayoutO, tla::Coord<tla::_0, tla::_0>, AscendC::TPosition::GM>; | ||
| 125 | + | ||
| 126 | + using CopyUbToGmO = Tile::CopyUb2GmTla<ArchTag, TensorUbO, TensorGmO>; | ||
| 127 | +}; | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | + | ||
| @@ -0,0 +1,66 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +namespace NpuArch::Gemm::Block { | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +template < | ||
| 22 | + class DispatchPolicy, | ||
| 23 | + class L1TileShape, | ||
| 24 | + class L0TileShape, | ||
| 25 | + class AType, | ||
| 26 | + class BType, | ||
| 27 | + class CType, | ||
| 28 | + class BiasType = void, | ||
| 29 | + class TileCopy = Gemm::Tile::TileCopy<typename DispatchPolicy::ArchTag, AType, BType, CType, BiasType>, | ||
| 30 | + class TileMmad = Gemm::Tile::TileMmad<typename DispatchPolicy::ArchTag, AType, BType, BiasType> | ||
| 31 | +> | ||
| 32 | +struct BlockMmad { | ||
| 33 | + static_assert(DEPENDENT_FALSE<DispatchPolicy>, "BlockMmad is not implemented for this DispatchPolicy"); | ||
| 34 | +}; | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| 38 | +template < | ||
| 39 | + class DispatchPolicy, | ||
| 40 | + class L1TileShape, | ||
| 41 | + class L0TileShape, | ||
| 42 | + class ElementA, | ||
| 43 | + class ElementB, | ||
| 44 | + class ElementC, | ||
| 45 | + class ElementBias = void, | ||
| 46 | + class TileCopy = Gemm::Tile::PackedTileCopyTla<typename DispatchPolicy::ArchTag, ElementA, layout::RowMajor, | ||
| 47 | + ElementB, layout::RowMajor, ElementC, layout::RowMajor, ElementBias>, | ||
| 48 | + class TileMmad = | ||
| 49 | + Gemm::Tile::TileMmadTla<typename DispatchPolicy::ArchTag, ElementA, typename TileCopy::LayoutTagL1A> | ||
| 50 | +> | ||
| 51 | +struct BlockMmadTla { | ||
| 52 | + static_assert(DEPENDENT_FALSE<DispatchPolicy>, "BlockMmadTla is not implemented for this DispatchPolicy"); | ||
| 53 | +}; | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +} // namespace NpuArch::Gemm::Block | ||
| 57 | + | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + | ||
| 65 | + | ||
| 66 | + | ||
| @@ -0,0 +1,80 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace NpuArch::Gemm::Block { | ||
| 17 | + | ||
| 18 | +struct Arch35MmadOpt { | ||
| 19 | + static constexpr int DYNAMIC_LOOP = -1; | ||
| 20 | + | ||
| 21 | + __aicore__ inline static bool UseM1N12(uint32_t mLoopNum, uint32_t nLoopNum) | ||
| 22 | + { | ||
| 23 | + return (mLoopNum == 1U) && (nLoopNum > 0U) && (nLoopNum <= 2U); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + __aicore__ inline static uint32_t LoopNum(uint32_t total, uint32_t tile) | ||
| 27 | + { | ||
| 28 | + return CeilDiv(total, tile); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + template <int STATIC_LOOP_NUM> | ||
| 32 | + __aicore__ inline static uint32_t LoopBound(uint32_t loopNum) | ||
| 33 | + { | ||
| 34 | + static_assert(STATIC_LOOP_NUM == DYNAMIC_LOOP || STATIC_LOOP_NUM > 0, | ||
| 35 | + "STATIC_LOOP_NUM must be -1 or positive"); | ||
| 36 | + if constexpr (STATIC_LOOP_NUM == DYNAMIC_LOOP) { | ||
| 37 | + return loopNum; | ||
| 38 | + } else { | ||
| 39 | + return static_cast<uint32_t>(STATIC_LOOP_NUM); | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + __aicore__ inline static uint32_t GetCurLoopCounter(uint32_t outerLoopItr, uint32_t loopNum) | ||
| 44 | + { | ||
| 45 | + return outerLoopItr * loopNum; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + __aicore__ inline static uint32_t MainLoopNum(uint32_t total, uint32_t tile) | ||
| 49 | + { | ||
| 50 | + uint32_t loopNum = LoopNum(total, tile); | ||
| 51 | + return (loopNum > 0U) ? (loopNum - 1U) : 0U; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + __aicore__ inline static uint32_t FinalTileSize(uint32_t total, uint32_t tile, uint32_t mainLoopNum) | ||
| 55 | + { | ||
| 56 | + return total - mainLoopNum * tile; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + template <uint32_t STAGES> | ||
| 60 | + __aicore__ inline static uint32_t StageId(uint32_t counter) | ||
| 61 | + { | ||
| 62 | + static_assert(STAGES > 0U, "STAGES must not be 0"); | ||
| 63 | + if constexpr ((STAGES & (STAGES - 1U)) == 0U) { | ||
| 64 | + return counter & (STAGES - 1U); | ||
| 65 | + } else { | ||
| 66 | + return counter % STAGES; | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + template <uint32_t ALIGN> | ||
| 71 | + __aicore__ inline static uint32_t AlignUpPow2(uint32_t value) | ||
| 72 | + { | ||
| 73 | + static_assert(ALIGN > 0U && ((ALIGN & (ALIGN - 1U)) == 0U), "ALIGN must be power of 2"); | ||
| 74 | + return (value + ALIGN - 1U) & ~(ALIGN - 1U); | ||
| 75 | + } | ||
| 76 | +}; | ||
| 77 | + | ||
| 78 | +} // namespace NpuArch::Gemm::Block | ||
| 79 | + | ||
| 80 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/gemm/block/block_mmad_pv.hpp+289-0
| @@ -0,0 +1,289 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +//////////////////////////////////////////////////////////////////// | ||
| 25 | + | ||
| 26 | +namespace NpuArch::Gemm::Block { | ||
| 27 | +//////////////////////////////////////////////////////////////////// | ||
| 28 | + | ||
| 29 | +template < | ||
| 30 | + bool PAGED_CACHE_FLAG_, | ||
| 31 | + bool ENABLE_UNIT_FLAG_, | ||
| 32 | + class L1TileShape_, | ||
| 33 | + class L0TileShape_, | ||
| 34 | + class AType_, | ||
| 35 | + class BType_, | ||
| 36 | + class CType_, | ||
| 37 | + class BiasType_, | ||
| 38 | + class TileCopy_, | ||
| 39 | + class TileMmad_> | ||
| 40 | +struct BlockMmad< | ||
| 41 | + MmadAtlasA2SFAIPV<PAGED_CACHE_FLAG_, ENABLE_UNIT_FLAG_>, | ||
| 42 | + L1TileShape_, | ||
| 43 | + L0TileShape_, | ||
| 44 | + AType_, | ||
| 45 | + BType_, | ||
| 46 | + CType_, | ||
| 47 | + BiasType_, | ||
| 48 | + TileCopy_, | ||
| 49 | + TileMmad_> { | ||
| 50 | +public: | ||
| 51 | + // Type Aliases | ||
| 52 | + using DispatchPolicy = MmadAtlasA2SFAIPV<PAGED_CACHE_FLAG_, ENABLE_UNIT_FLAG_>; | ||
| 53 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 54 | + using L1TileShape = L1TileShape_; | ||
| 55 | + using L0TileShape = L0TileShape_; | ||
| 56 | + using ElementA = typename AType_::Element; | ||
| 57 | + using LayoutA = typename AType_::Layout; | ||
| 58 | + using ElementB = typename BType_::Element; | ||
| 59 | + using LayoutB = typename BType_::Layout; | ||
| 60 | + using ElementC = typename CType_::Element; | ||
| 61 | + using LayoutC = typename CType_::Layout; | ||
| 62 | + using TileMmad = TileMmad_; | ||
| 63 | + using CopyGmToL1A = typename TileCopy_::CopyGmToL1A; | ||
| 64 | + using CopyGmToL1B = typename TileCopy_::CopyGmToL1B; | ||
| 65 | + using CopyL1ToL0A = typename TileCopy_::CopyL1ToL0A; | ||
| 66 | + using CopyL1ToL0B = typename TileCopy_::CopyL1ToL0B; | ||
| 67 | + using CopyL0CToGm = typename TileCopy_::CopyL0CToGm; | ||
| 68 | + using ElementAccumulator = | ||
| 69 | + typename Gemm::helper::ElementAccumulatorSelector<ElementA, ElementB>::ElementAccumulator; | ||
| 70 | + using LayoutAInL1 = typename CopyL1ToL0A::LayoutSrc; | ||
| 71 | + using LayoutBInL1 = typename CopyL1ToL0B::LayoutSrc; | ||
| 72 | + using LayoutAInL0 = typename CopyL1ToL0A::LayoutDst; | ||
| 73 | + using LayoutBInL0 = typename CopyL1ToL0B::LayoutDst; | ||
| 74 | + using LayoutCInL0 = layout::zN; | ||
| 75 | + | ||
| 76 | + using L1AAlignHelper = Gemm::helper::L1AlignHelper<ElementA, LayoutA>; | ||
| 77 | + using L1BAlignHelper = Gemm::helper::L1AlignHelper<ElementB, LayoutB>; | ||
| 78 | + | ||
| 79 | + static constexpr uint32_t STAGES = DispatchPolicy::STAGES; | ||
| 80 | + static constexpr uint32_t L1A_SIZE = L1TileShape::M * L1TileShape::K * sizeof(ElementA); | ||
| 81 | + static constexpr uint32_t L1B_SIZE = L1TileShape::N * L1TileShape::K * sizeof(ElementB); | ||
| 82 | + static constexpr uint32_t L0A_SIZE = ArchTag::L0A_SIZE; | ||
| 83 | + static constexpr uint32_t L0B_SIZE = ArchTag::L0B_SIZE; | ||
| 84 | + static constexpr uint32_t L0C_SIZE = ArchTag::L0C_SIZE; | ||
| 85 | + static constexpr uint32_t L0A_PINGPONG_BUF_SIZE = L0A_SIZE / STAGES; | ||
| 86 | + static constexpr uint32_t L0B_PINGPONG_BUF_SIZE = L0B_SIZE / STAGES; | ||
| 87 | + static constexpr uint32_t L0C_PINGPONG_BUF_SIZE = L0C_SIZE / STAGES; | ||
| 88 | + | ||
| 89 | + // Check LayoutC | ||
| 90 | + static_assert(std::is_same_v<LayoutC, layout::RowMajor>, "LayoutC only support RowMajor yet!"); | ||
| 91 | + | ||
| 92 | + /// Construct | ||
| 93 | + __aicore__ inline | ||
| 94 | + BlockMmad(Arch::Resource<ArchTag> &resource, uint32_t l1BufAddrStart = 0) | ||
| 95 | + { | ||
| 96 | + // Allocate L1 memory space | ||
| 97 | + l1BTensor = resource.l1Buf.template GetBufferByByte<ElementB>(l1BufAddrStart + L1A_SIZE * 2); | ||
| 98 | + for (uint32_t i = 0; i < STAGES; i++) { | ||
| 99 | + l1ATensor[i] = resource.l1Buf.template GetBufferByByte<ElementA>(l1BufAddrStart + L1A_SIZE * i); | ||
| 100 | + l0ATensor[i] = resource.l0ABuf.template GetBufferByByte<ElementA>(L0A_PINGPONG_BUF_SIZE * i); | ||
| 101 | + l0BTensor[i] = resource.l0BBuf.template GetBufferByByte<ElementB>(L0B_PINGPONG_BUF_SIZE * i); | ||
| 102 | + l0CTensor[i] = resource.l0CBuf.template GetBufferByByte<ElementAccumulator>(L0C_PINGPONG_BUF_SIZE * i); | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + /// Destructor | ||
| 107 | + __aicore__ inline | ||
| 108 | + ~BlockMmad() {} | ||
| 109 | + | ||
| 110 | + __aicore__ inline | ||
| 111 | + void getBlockShape( | ||
| 112 | + GemmCoord &actualShape, uint32_t &nowNIdx, uint32_t &nLoop, uint32_t &stackSeqTile, uint32_t &blockSize) | ||
| 113 | + { | ||
| 114 | + uint32_t nSplitSize = blockSize; | ||
| 115 | + if (nowNIdx == nLoop - 1) { | ||
| 116 | + nSplitSize = stackSeqTile - nowNIdx * blockSize; | ||
| 117 | + } | ||
| 118 | + actualShape[2] = nSplitSize; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + __aicore__ inline | ||
| 122 | + void operator()(AscendC::GlobalTensor<ElementA> gA, | ||
| 123 | + AscendC::GlobalTensor<ElementB> gB, | ||
| 124 | + AscendC::GlobalTensor<ElementC> gC, | ||
| 125 | + AscendC::GlobalTensor<int32_t> gBlockTable, | ||
| 126 | + AscendC::GlobalTensor<int32_t> gSelectIdx, | ||
| 127 | + LayoutA layoutA, LayoutB layoutB, LayoutC layoutC,GemmCoord actualOriShape, | ||
| 128 | + uint32_t &nIdx, uint32_t &nLoop, uint32_t &blockSize, uint32_t kvSeqlen, uint32_t strideKV, | ||
| 129 | + uint32_t blockStackNum, Arch::CrossCoreFlag softmaxFlag, | ||
| 130 | + uint32_t &y, uint32_t &selectNum, uint32_t &kvYBlockNum) | ||
| 131 | + { | ||
| 132 | + uint32_t rowNum = actualOriShape[0]; | ||
| 133 | + uint32_t embed = actualOriShape[1]; | ||
| 134 | + uint32_t stackSeqTile = actualOriShape[2]; | ||
| 135 | + GemmCoord actualShape{rowNum, embed, 0}; | ||
| 136 | + | ||
| 137 | + // load V | ||
| 138 | + LayoutBInL1 layoutBInL1 = LayoutBInL1::template MakeLayout<ElementB>(stackSeqTile, embed); | ||
| 139 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID4); | ||
| 140 | + uint32_t nL1Loop = CeilDiv<L1TileShape::N>(stackSeqTile); | ||
| 141 | + | ||
| 142 | + for (uint32_t blockStackIdx = 0; blockStackIdx < nL1Loop; ++blockStackIdx) { | ||
| 143 | + uint32_t nowNIdx = nIdx + blockStackIdx; | ||
| 144 | + getBlockShape(actualShape, blockStackIdx, nL1Loop, stackSeqTile, blockSize); | ||
| 145 | + uint32_t kActual = actualShape.k(); | ||
| 146 | + uint32_t nActual = actualShape.n(); | ||
| 147 | + | ||
| 148 | + uint32_t processSize = 0; | ||
| 149 | + uint32_t nBlockOffset = nowNIdx * blockSize; | ||
| 150 | + uint32_t currentSelectYIdx = nBlockOffset / y; | ||
| 151 | + uint32_t currentYoffset = nBlockOffset % y; | ||
| 152 | + uint32_t currentYIdx = gSelectIdx.GetValue(currentSelectYIdx); | ||
| 153 | + uint32_t offsetInKV = currentYIdx * y + currentYoffset; | ||
| 154 | + | ||
| 155 | + while (processSize < kActual && currentSelectYIdx < selectNum && currentYIdx < kvYBlockNum && offsetInKV < kvSeqlen) { | ||
| 156 | + uint32_t yAcutal = (currentSelectYIdx == selectNum - 1 && currentYIdx == kvYBlockNum - 1 && kvSeqlen % y != 0) ? | ||
| 157 | + (kvSeqlen - y * currentYIdx) : y; | ||
| 158 | + uint32_t remainingInYBlock = yAcutal - currentYoffset; | ||
| 159 | + uint32_t remainingInNBlock = kActual - processSize; | ||
| 160 | + | ||
| 161 | + uint32_t actualYSize = min(remainingInNBlock, remainingInYBlock); | ||
| 162 | + if (actualYSize == 0) { | ||
| 163 | + break; | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + auto layoutBTile = layoutB.GetTileLayout(MakeCoord(actualYSize, nActual)); | ||
| 167 | + MatrixCoord l1BTileCoord{blockStackIdx * blockSize + processSize, 0}; | ||
| 168 | + auto l1BTile = l1BTensor[layoutBInL1.GetOffset(l1BTileCoord)]; | ||
| 169 | + | ||
| 170 | + copyGmToL1B(l1BTile, gB[offsetInKV * strideKV], layoutBInL1, layoutBTile); | ||
| 171 | + | ||
| 172 | + processSize += actualYSize; | ||
| 173 | + currentYoffset += actualYSize; | ||
| 174 | + offsetInKV += actualYSize; | ||
| 175 | + | ||
| 176 | + if (currentYoffset >= yAcutal) { | ||
| 177 | + currentSelectYIdx++; | ||
| 178 | + if (currentSelectYIdx >= selectNum) { | ||
| 179 | + break; | ||
| 180 | + } | ||
| 181 | + currentYoffset = 0; | ||
| 182 | + currentYIdx = gSelectIdx.GetValue(currentSelectYIdx); | ||
| 183 | + offsetInKV = currentYIdx * y; | ||
| 184 | + } | ||
| 185 | + } | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(EVENT_ID0); | ||
| 189 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(EVENT_ID0); | ||
| 190 | + | ||
| 191 | + Arch::CrossCoreWaitFlag(softmaxFlag); | ||
| 192 | + | ||
| 193 | + uint32_t mL1Loop = CeilDiv<L1TileShape::M>(rowNum); | ||
| 194 | + uint32_t kL1Loop = CeilDiv<L1TileShape::K>(stackSeqTile); | ||
| 195 | + for (uint32_t mL1Idx = 0; mL1Idx < mL1Loop; mL1Idx++) { | ||
| 196 | + uint32_t mL1Actual = (mL1Idx < mL1Loop - 1) ? L1TileShape::M : (rowNum - mL1Idx * L1TileShape::M); | ||
| 197 | + uint32_t mRound = RoundUp<L1AAlignHelper::M_ALIGNED>(mL1Actual); | ||
| 198 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(l0CPingPongFlag); | ||
| 199 | + for (uint32_t kL1Idx = 0; kL1Idx < kL1Loop; kL1Idx++) { | ||
| 200 | + uint32_t kL1Actual = (kL1Idx < kL1Loop - 1) ? L1TileShape::K : (stackSeqTile - kL1Idx * L1TileShape::K); | ||
| 201 | + | ||
| 202 | + // load P | ||
| 203 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1PPingPongFlag); | ||
| 204 | + MatrixCoord gmATileCoord{mL1Idx * L1TileShape::M, kL1Idx * L1TileShape::K}; | ||
| 205 | + auto gmTileA = gA[layoutA.GetOffset(gmATileCoord)]; | ||
| 206 | + auto layoutTileA = layoutA.GetTileLayout(MakeCoord(mL1Actual, kL1Actual)); | ||
| 207 | + LayoutAInL1 layoutAInL1 = LayoutAInL1::template MakeLayout<ElementA>(mL1Actual, kL1Actual); | ||
| 208 | + copyGmToL1A(l1ATensor[l1PPingPongFlag], gmTileA, layoutAInL1, layoutTileA); | ||
| 209 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1PPingPongFlag); | ||
| 210 | + | ||
| 211 | + uint32_t kL0Loop = CeilDiv<L0TileShape::K>(kL1Actual); | ||
| 212 | + for (uint32_t kL0Idx = 0; kL0Idx < kL0Loop; kL0Idx++) { | ||
| 213 | + uint32_t kL0Actual = | ||
| 214 | + (kL0Idx < kL0Loop - 1) ? L0TileShape::K : (kL1Actual - kL0Idx * L0TileShape::K); | ||
| 215 | + | ||
| 216 | + LayoutAInL0 layoutAInL0 = LayoutAInL0::template MakeLayout<ElementA>(mL1Actual, kL0Actual); | ||
| 217 | + MatrixCoord l1ATileCoord{0, kL0Idx * L0TileShape::K}; | ||
| 218 | + auto l1ATile = l1ATensor[l1PPingPongFlag][layoutAInL1.GetOffset(l1ATileCoord)]; | ||
| 219 | + | ||
| 220 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0ABPingPongFlag); | ||
| 221 | + if (kL0Idx == 0) { | ||
| 222 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1PPingPongFlag); | ||
| 223 | + } | ||
| 224 | + copyL1ToL0A(l0ATensor[l0ABPingPongFlag], l1ATile, layoutAInL0, layoutAInL1); | ||
| 225 | + if (kL0Idx == kL0Loop - 1) { | ||
| 226 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(l1PPingPongFlag); | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + LayoutBInL0 layoutBInL0 = LayoutBInL0::template MakeLayout<ElementB>(kL0Actual, embed); | ||
| 230 | + MatrixCoord l1BTileCoord{kL1Idx * L1TileShape::K + kL0Idx * L0TileShape::K, 0}; | ||
| 231 | + auto l1BTile = l1BTensor[layoutBInL1.GetOffset(l1BTileCoord)]; | ||
| 232 | + | ||
| 233 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0ABPingPongFlag + 2); | ||
| 234 | + copyL1ToL0B(l0BTensor[l0ABPingPongFlag], l1BTile, layoutBInL0, layoutBInL1); | ||
| 235 | + | ||
| 236 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(EVENT_ID0); | ||
| 237 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(EVENT_ID0); | ||
| 238 | + bool initMmad = kL1Idx == 0 && kL0Idx == 0; | ||
| 239 | + tileMmad(l0CTensor[l0CPingPongFlag], | ||
| 240 | + l0ATensor[l0ABPingPongFlag], | ||
| 241 | + l0BTensor[l0ABPingPongFlag], | ||
| 242 | + mRound, | ||
| 243 | + embed, | ||
| 244 | + kL0Actual, | ||
| 245 | + initMmad); | ||
| 246 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0ABPingPongFlag); | ||
| 247 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0ABPingPongFlag + 2); | ||
| 248 | + l0ABPingPongFlag = 1 - l0ABPingPongFlag; | ||
| 249 | + } | ||
| 250 | + l1PPingPongFlag = 1 - l1PPingPongFlag; | ||
| 251 | + } | ||
| 252 | + AscendC::SetFlag<AscendC::HardEvent::M_FIX>(EVENT_ID0); | ||
| 253 | + AscendC::WaitFlag<AscendC::HardEvent::M_FIX>(EVENT_ID0); | ||
| 254 | + MatrixCoord gmCTileCoord{mL1Idx * L0TileShape::M, 0}; | ||
| 255 | + LayoutC layoutCTile = layoutC.GetTileLayout(MakeCoord(mL1Actual, embed)); | ||
| 256 | + auto layoutInL0C = LayoutCInL0::MakeLayoutInL0C(MakeCoord(mL1Actual, embed)); | ||
| 257 | + copyL0CToGm(gC[layoutC.GetOffset(gmCTileCoord)], l0CTensor[l0CPingPongFlag], layoutCTile, layoutInL0C); | ||
| 258 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(l0CPingPongFlag); | ||
| 259 | + l0CPingPongFlag = 1 - l0CPingPongFlag; | ||
| 260 | + } | ||
| 261 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID4); | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | +protected: | ||
| 265 | + /// Data members | ||
| 266 | + AscendC::LocalTensor<ElementA> l1ATensor[STAGES]; | ||
| 267 | + AscendC::LocalTensor<ElementB> l1BTensor; | ||
| 268 | + AscendC::LocalTensor<ElementA> l0ATensor[STAGES]; | ||
| 269 | + AscendC::LocalTensor<ElementB> l0BTensor[STAGES]; | ||
| 270 | + AscendC::LocalTensor<ElementAccumulator> l0CTensor[STAGES]; | ||
| 271 | + | ||
| 272 | + TileMmad tileMmad; | ||
| 273 | + CopyGmToL1A copyGmToL1A; | ||
| 274 | + CopyGmToL1B copyGmToL1B; | ||
| 275 | + CopyL1ToL0A copyL1ToL0A; | ||
| 276 | + CopyL1ToL0B copyL1ToL0B; | ||
| 277 | + CopyL0CToGm copyL0CToGm; | ||
| 278 | + | ||
| 279 | + uint32_t l1PPingPongFlag = 0; | ||
| 280 | + uint32_t l0CPingPongFlag = 0; | ||
| 281 | + uint32_t l0ABPingPongFlag = 0; | ||
| 282 | +}; | ||
| 283 | + | ||
| 284 | +//////////////////////////////////////////////////////////////////// | ||
| 285 | + | ||
| 286 | +} // namespace NpuArch::Gemm::Block | ||
| 287 | + | ||
| 288 | + | ||
| 289 | + | ||
| @@ -0,0 +1,462 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @brief matmul implementation for single p&v base tile | ||
| 13 | + * This implementation is designed for the following senario: | ||
| 14 | + * A full p base tile is loaded to L1 from UB, no workspace transit | ||
| 15 | + * A full v base tile is loaded to L1 from GM,relavent instructions launched before p base tile crossCore wait | ||
| 16 | + * A full p*v base tile is loaded to UB from l0C, no workspace transit | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | +//////////////////////////////////////////////////////////////////// | ||
| 35 | + | ||
| 36 | +namespace NpuArch::Gemm::Block { | ||
| 37 | +//////////////////////////////////////////////////////////////////// | ||
| 38 | + | ||
| 39 | +struct Mm2L1TileHelper { | ||
| 40 | + uint32_t mm2L1TileM; | ||
| 41 | + uint32_t mm2L1TileN; | ||
| 42 | + uint32_t mm2L1TileKLeft; | ||
| 43 | + uint32_t mm2L1TileKRight; | ||
| 44 | + uint32_t pL1BufNum; | ||
| 45 | + uint32_t vL1BufNum; | ||
| 46 | + | ||
| 47 | + __aicore__ inline | ||
| 48 | + Mm2L1TileHelper() {} | ||
| 49 | + | ||
| 50 | + __aicore__ inline | ||
| 51 | + Mm2L1TileHelper( | ||
| 52 | + uint32_t m, | ||
| 53 | + uint32_t n, | ||
| 54 | + uint32_t kl, | ||
| 55 | + uint32_t kr, | ||
| 56 | + uint32_t pbn, | ||
| 57 | + uint32_t vbn) : | ||
| 58 | + mm2L1TileM(m), | ||
| 59 | + mm2L1TileN(n), | ||
| 60 | + mm2L1TileKLeft(kl), | ||
| 61 | + mm2L1TileKRight(kr), | ||
| 62 | + pL1BufNum(pbn), | ||
| 63 | + vL1BufNum(vbn) {} | ||
| 64 | +}; | ||
| 65 | + | ||
| 66 | +template < | ||
| 67 | + class L1TileShape_, | ||
| 68 | + class L0TileShape_, | ||
| 69 | + class ElementA_, | ||
| 70 | + class ElementB_, | ||
| 71 | + class ElementC_, | ||
| 72 | + class ElementBias_, | ||
| 73 | + class TileCopy_, | ||
| 74 | + class TileMmad_> | ||
| 75 | +struct BlockMmadTla< | ||
| 76 | + MmadAtlasA5BsaPV, | ||
| 77 | + L1TileShape_, | ||
| 78 | + L0TileShape_, | ||
| 79 | + ElementA_, | ||
| 80 | + ElementB_, | ||
| 81 | + ElementC_, | ||
| 82 | + ElementBias_, | ||
| 83 | + TileCopy_, | ||
| 84 | + TileMmad_> | ||
| 85 | +{ | ||
| 86 | +public: | ||
| 87 | + using DispatchPolicy = MmadAtlasA5BsaPV; | ||
| 88 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 89 | + using TileCopy = TileCopy_; | ||
| 90 | + using ElementA = ElementA_; | ||
| 91 | + using ElementB = ElementB_; | ||
| 92 | + using ElementC = ElementC_; | ||
| 93 | + | ||
| 94 | + using TileMmad = TileMmad_; | ||
| 95 | + | ||
| 96 | + using CopyL1ToL0A = typename TileCopy::CopyL1ToL0A; | ||
| 97 | + using CopyL1ToL0B = typename TileCopy::CopyL1ToL0B; | ||
| 98 | + | ||
| 99 | + using ElementAccumulator = typename TileCopy::ElementAccumulator; | ||
| 100 | + | ||
| 101 | + using LayoutTagL1A = typename TileCopy::LayoutTagL1A; | ||
| 102 | + using LayoutTagL1B = typename TileCopy::LayoutTagL1B; | ||
| 103 | + using LayoutTagL0A = typename TileCopy::LayoutTagL0A; | ||
| 104 | + using LayoutTagL0B = typename TileCopy::LayoutTagL0B; | ||
| 105 | + | ||
| 106 | + static constexpr uint32_t L0_STAGES = DispatchPolicy::L0_STAGES; | ||
| 107 | + static constexpr uint32_t L0_TILE_M = tla::get<0>(L0TileShape_{}); | ||
| 108 | + static constexpr uint32_t L0_TILE_N = tla::get<1>(L0TileShape_{}); | ||
| 109 | + static constexpr uint32_t L0_TILE_K = tla::get<2>(L0TileShape_{}); | ||
| 110 | + static constexpr uint32_t L0A_PINGPONG_BUF_SIZE = ArchTag::L0A_SIZE / L0_STAGES; | ||
| 111 | + static constexpr uint32_t L0B_PINGPONG_BUF_SIZE = ArchTag::L0B_SIZE / L0_STAGES; | ||
| 112 | + static constexpr uint32_t L0C_HALF_BUF_SIZE = ArchTag::L0C_SIZE / 2; | ||
| 113 | + static constexpr uint32_t L0C_PINGPONG_BUF_SIZE = L0C_HALF_BUF_SIZE / L0_STAGES; | ||
| 114 | + | ||
| 115 | + static constexpr uint32_t MAX_L1_STAGES = 3; // 编译期常量,为静态L1Tensor数组开辟准备。取一个buffer份数的极大值 | ||
| 116 | + static constexpr uint32_t V0_V1_FLAG_ID_OFFSET = 16; // 核间同步mode4,AIC侧需要两个flagId分别对应两个AIV | ||
| 117 | + static constexpr uint32_t VSDB_BUF_NUM = 2; | ||
| 118 | + static constexpr uint32_t VSDB_BUF_SIZE = 256 * sizeof(uint64_t); | ||
| 119 | + static constexpr bool enFixpipeDequant = false; | ||
| 120 | + | ||
| 121 | + __aicore__ inline | ||
| 122 | + BlockMmadTla(Arch::Resource<ArchTag> &resource, uint32_t l1BufAddrStart, Mm2L1TileHelper &mm2L1TileHelper) | ||
| 123 | + { | ||
| 124 | + l1ATileM = mm2L1TileHelper.mm2L1TileM; | ||
| 125 | + l1BTileN = mm2L1TileHelper.mm2L1TileN; | ||
| 126 | + l1ATileK = mm2L1TileHelper.mm2L1TileKLeft; | ||
| 127 | + l1BTileK = mm2L1TileHelper.mm2L1TileKRight; | ||
| 128 | + l1ABufNum = mm2L1TileHelper.pL1BufNum; | ||
| 129 | + l1BBufNum = mm2L1TileHelper.vL1BufNum; | ||
| 130 | + for (uint32_t i = 0; i < l1ABufNum; i++) { | ||
| 131 | + l1ATensor[i] = resource.l1Buf.template GetBufferByByte<ElementA>( | ||
| 132 | + l1BufAddrStart + l1ATileM * l1ATileK * sizeof(ElementA) * i); | ||
| 133 | + } | ||
| 134 | + for (uint32_t i = 0; i < l1BBufNum; i++) { | ||
| 135 | + l1BTensor[i] = resource.l1Buf.template GetBufferByByte<ElementB>( | ||
| 136 | + l1BufAddrStart + l1ATileM * l1ATileK * sizeof(ElementA) * l1ABufNum + | ||
| 137 | + l1BTileK * l1BTileN * sizeof(ElementB) * i); | ||
| 138 | + } | ||
| 139 | + for (uint32_t i = 0; i < L0_STAGES; i++) { | ||
| 140 | + l0ATensor[i] = resource.l0ABuf.template GetBufferByByte<ElementA>( | ||
| 141 | + L0A_PINGPONG_BUF_SIZE * i); | ||
| 142 | + l0BTensor[i] = resource.l0BBuf.template GetBufferByByte<ElementB>( | ||
| 143 | + L0B_PINGPONG_BUF_SIZE * i); | ||
| 144 | + l0CTensor[i] = resource.l0CBuf.template GetBufferByByte<ElementAccumulator>( | ||
| 145 | + L0C_HALF_BUF_SIZE + L0C_PINGPONG_BUF_SIZE * i); | ||
| 146 | + } | ||
| 147 | + uint32_t vsdbL1AddrStart = ArchTag::L1_SIZE - VSDB_BUF_NUM * VSDB_BUF_SIZE; | ||
| 148 | + for (uint32_t i = 0; i < VSDB_BUF_NUM; i++) { | ||
| 149 | + l1VSDBTensor[i] = resource.l1Buf.template GetBufferByByte<uint64_t>( | ||
| 150 | + vsdbL1AddrStart + VSDB_BUF_SIZE * i); | ||
| 151 | + } | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + /// Destructor | ||
| 155 | + __aicore__ inline | ||
| 156 | + ~BlockMmadTla() {} | ||
| 157 | + | ||
| 158 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 159 | + __aicore__ inline | ||
| 160 | + void SetCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 161 | + { | ||
| 162 | + // in mode 4, AIC set for 2 AIVs seperately | ||
| 163 | + if constexpr (MODE == 4U) { | ||
| 164 | + uint16_t flagIdV0 = crossCoreFlag.id; | ||
| 165 | + uint16_t flagIdV1 = flagIdV0 + V0_V1_FLAG_ID_OFFSET; | ||
| 166 | + Arch::CrossCoreFlag crossCoreFlagV1(flagIdV1); | ||
| 167 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlag); | ||
| 168 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlagV1); | ||
| 169 | + } | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 173 | + __aicore__ inline | ||
| 174 | + void WaitCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 175 | + { | ||
| 176 | + // in mode 4, AIC wait for 2 AIVs seperately | ||
| 177 | + if constexpr (MODE == 4U) { | ||
| 178 | + uint16_t flagIdV0 = crossCoreFlag.id; | ||
| 179 | + uint16_t flagIdV1 = flagIdV0 + V0_V1_FLAG_ID_OFFSET; | ||
| 180 | + Arch::CrossCoreFlag crossCoreFlagV1(flagIdV1); | ||
| 181 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlag); | ||
| 182 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlagV1); | ||
| 183 | + } | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + __aicore__ inline | ||
| 187 | + uint32_t GetCurLoopCounter(uint32_t outterLoopItr, uint32_t curLoopNum, uint32_t curLoopItr) | ||
| 188 | + { | ||
| 189 | + return outterLoopItr * curLoopNum + curLoopItr; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + template <class TensorB, class TensorL1B> | ||
| 193 | + __aicore__ inline | ||
| 194 | + void SparseVBaseTileL1FullLoad(TensorB &gBTensor, TensorL1B &l1BTensorTla, | ||
| 195 | + AscendC::GlobalTensor<int32_t> gSparseBlockIdx, | ||
| 196 | + uint32_t gatheredKvSTileIdx, uint32_t kvSeqlen, | ||
| 197 | + uint32_t kvSBaseTile, uint32_t blockShapeY, | ||
| 198 | + uint32_t yBlockNumAval, uint32_t yBlockNumRsvd, | ||
| 199 | + uint32_t curBaseTileSize, uint32_t embed) | ||
| 200 | + { | ||
| 201 | + using CopyGmToL1B = typename TileCopy_::template CopyGmToL1B<TensorB>; | ||
| 202 | + CopyGmToL1B copyGmToL1B; | ||
| 203 | + uint32_t baseTileStartOffset = gatheredKvSTileIdx * kvSBaseTile; | ||
| 204 | + uint32_t baseTileEndOffset = baseTileStartOffset + curBaseTileSize; | ||
| 205 | + // 稀疏情况下对实际选中的部分gather后进行基本块切分 | ||
| 206 | + // 当前处理的Yblock在gather的序列中的起始偏移,初始值为当前基块的起始偏移 | ||
| 207 | + uint32_t gatheredStartOffset = baseTileStartOffset; | ||
| 208 | + // 当前处理的Yblock gather后的下标,初始值为基本块起始偏移对应的按Y方向稀疏block的gather后起始下标 | ||
| 209 | + uint32_t gatheredYBlockIdx = gatheredStartOffset / blockShapeY; | ||
| 210 | + // 当前基本块起始偏移对应的按Y方向稀疏后的block内起始偏移 | ||
| 211 | + uint32_t yBlockInnerStartOffset = gatheredStartOffset % blockShapeY; | ||
| 212 | + // 当前处理的Yblock原始的下标,初始值为基本块对应的按Y方向稀疏block的原始起始下标 | ||
| 213 | + uint32_t oriYBlockIdx = gSparseBlockIdx.GetValue(gatheredYBlockIdx); | ||
| 214 | + // 当前处理的Yblock起始位置在原始序列中的偏移,初始值为基本块在原始序列中的起始偏移 | ||
| 215 | + uint32_t oriStartOffset = oriYBlockIdx * blockShapeY + yBlockInnerStartOffset; | ||
| 216 | + // 逐稀疏block搬移填充基本块过程中,已处理的累积序列长度 | ||
| 217 | + uint32_t dealtLenAccum = 0; | ||
| 218 | + | ||
| 219 | + while (dealtLenAccum < curBaseTileSize && gatheredYBlockIdx < yBlockNumRsvd && | ||
| 220 | + oriYBlockIdx < yBlockNumAval && oriStartOffset < kvSeqlen) { | ||
| 221 | + uint32_t curYBlockSize = blockShapeY; | ||
| 222 | + if (oriYBlockIdx == yBlockNumAval - 1) { | ||
| 223 | + curYBlockSize = kvSeqlen - oriYBlockIdx * blockShapeY; | ||
| 224 | + } | ||
| 225 | + uint32_t gatheredEndOffset = | ||
| 226 | + min(gatheredYBlockIdx * blockShapeY + curYBlockSize, | ||
| 227 | + baseTileEndOffset); | ||
| 228 | + // 当前循环处理的序列长度 | ||
| 229 | + uint32_t curDealtLen = gatheredEndOffset - gatheredStartOffset; | ||
| 230 | + if (curDealtLen == 0) { | ||
| 231 | + break; | ||
| 232 | + } | ||
| 233 | + auto l1BTensorTlaTile = GetTile(l1BTensorTla, | ||
| 234 | + tla::MakeCoord(dealtLenAccum, 0), tla::MakeShape(curDealtLen, embed)); | ||
| 235 | + auto gBTensorTlaTile = GetTile(gBTensor, | ||
| 236 | + tla::MakeCoord(oriStartOffset, 0), tla::MakeShape(curDealtLen, embed)); | ||
| 237 | + copyGmToL1B(l1BTensorTlaTile, gBTensorTlaTile); | ||
| 238 | + // 为下一次循环刷新循环变量 | ||
| 239 | + dealtLenAccum += curDealtLen; | ||
| 240 | + gatheredStartOffset += curDealtLen; | ||
| 241 | + gatheredYBlockIdx = gatheredStartOffset / blockShapeY; | ||
| 242 | + yBlockInnerStartOffset = gatheredStartOffset % blockShapeY; | ||
| 243 | + if (dealtLenAccum < curBaseTileSize) { | ||
| 244 | + // 防止最后一次循环之后对GM的访问越界引发硬件error | ||
| 245 | + oriYBlockIdx = gSparseBlockIdx.GetValue(gatheredYBlockIdx); | ||
| 246 | + oriStartOffset = oriYBlockIdx * blockShapeY + yBlockInnerStartOffset; | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + | ||
| 252 | + | ||
| 253 | + template < | ||
| 254 | + int staticML0LoopNum = Arch35MmadOpt::DYNAMIC_LOOP, | ||
| 255 | + int staticNL0LoopNum = Arch35MmadOpt::DYNAMIC_LOOP, | ||
| 256 | + class TensorB, | ||
| 257 | + class TensorC> | ||
| 258 | + __aicore__ inline | ||
| 259 | + void operator()(TensorB &gBTensor, TensorC &ubCTensor, | ||
| 260 | + AscendC::GlobalTensor<int32_t> gSparseBlockIdx, | ||
| 261 | + GemmCoord actualOriShape, | ||
| 262 | + uint32_t gatheredKvSTileIdx, uint32_t kvSeqlen, | ||
| 263 | + uint32_t kvSBaseTile, uint32_t blockShapeY, | ||
| 264 | + uint32_t yBlockNumAval, uint32_t yBlockNumRsvd, | ||
| 265 | + uint64_t prefixSumL0AStages, uint64_t prefixSumL0BStages, | ||
| 266 | + Arch::CrossCoreFlag smToMm2Flag, Arch::CrossCoreFlag mm2ToReFlag) | ||
| 267 | + { | ||
| 268 | + struct EmptyTensor {}; | ||
| 269 | + EmptyTensor dummyVS; | ||
| 270 | + this->operator()<0, staticML0LoopNum, staticNL0LoopNum>( | ||
| 271 | + gBTensor, ubCTensor, dummyVS, gSparseBlockIdx, | ||
| 272 | + actualOriShape, gatheredKvSTileIdx, kvSeqlen, | ||
| 273 | + kvSBaseTile, blockShapeY, yBlockNumAval, | ||
| 274 | + yBlockNumRsvd, prefixSumL0AStages, prefixSumL0BStages, smToMm2Flag, mm2ToReFlag); | ||
| 275 | + } | ||
| 276 | + | ||
| 277 | + | ||
| 278 | + template < | ||
| 279 | + int quant_mode, | ||
| 280 | + int staticML0LoopNum = Arch35MmadOpt::DYNAMIC_LOOP, | ||
| 281 | + int staticNL0LoopNum = Arch35MmadOpt::DYNAMIC_LOOP, | ||
| 282 | + class TensorB, | ||
| 283 | + class TensorC, | ||
| 284 | + class TensorVS> | ||
| 285 | + __aicore__ inline | ||
| 286 | + void operator()(TensorB &gBTensor, TensorC &ubCTensor, TensorVS &gVSTensor, | ||
| 287 | + AscendC::GlobalTensor<int32_t> gSparseBlockIdx, | ||
| 288 | + GemmCoord actualOriShape, | ||
| 289 | + uint32_t gatheredKvSTileIdx, uint32_t kvSeqlen, | ||
| 290 | + uint32_t kvSBaseTile, uint32_t blockShapeY, | ||
| 291 | + uint32_t yBlockNumAval, uint32_t yBlockNumRsvd, | ||
| 292 | + uint64_t prefixSumL0AStages, uint64_t prefixSumL0BStages, | ||
| 293 | + Arch::CrossCoreFlag smToMm2Flag, Arch::CrossCoreFlag mm2ToReFlag) | ||
| 294 | + { | ||
| 295 | + using CopyL0CToDst = typename TileCopy_::template CopyL0CToDst<TensorC>; | ||
| 296 | + CopyL0CToDst copyL0CToDst; | ||
| 297 | + | ||
| 298 | + uint32_t rowNum = actualOriShape[0]; | ||
| 299 | + uint32_t embed = actualOriShape[1]; | ||
| 300 | + uint32_t curBaseTileSize = actualOriShape[2]; | ||
| 301 | + | ||
| 302 | + uint32_t l1BBufId = gatheredKvSTileIdx % l1BBufNum; | ||
| 303 | + uint32_t l1BEventId = l1BBufId + 3; | ||
| 304 | + uint32_t l1ABufId = gatheredKvSTileIdx % l1ABufNum; | ||
| 305 | + | ||
| 306 | + auto l1BLayoutTla = tla::MakeLayout<ElementB, LayoutTagL1B>(curBaseTileSize, embed); | ||
| 307 | + auto l1BTensorTla = tla::MakeTensor(l1BTensor[l1BBufId], l1BLayoutTla, Arch::PositionL1{}); | ||
| 308 | + auto l1ALayoutTla = tla::MakeLayout<ElementA, LayoutTagL1A>(rowNum, curBaseTileSize); | ||
| 309 | + auto l1ATensorTla = tla::MakeTensor(l1ATensor[l1ABufId], l1ALayoutTla, Arch::PositionL1{}); | ||
| 310 | + // load V full base tile to L1 before crossCoreSync | ||
| 311 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BEventId); | ||
| 312 | + SparseVBaseTileL1FullLoad( | ||
| 313 | + gBTensor, l1BTensorTla, gSparseBlockIdx, gatheredKvSTileIdx, kvSeqlen, kvSBaseTile, blockShapeY, | ||
| 314 | + yBlockNumAval, yBlockNumRsvd, curBaseTileSize, embed); | ||
| 315 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1BEventId); | ||
| 316 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1BEventId); | ||
| 317 | + // fwd crossCoreSync from online sm to mm2 | ||
| 318 | + WaitCrossCoreSync<4, PIPE_MTE1>(smToMm2Flag); | ||
| 319 | + // P full base tile already on L1 | ||
| 320 | + uint32_t mL0LoopNum = Arch35MmadOpt::LoopNum(rowNum, L0_TILE_M); | ||
| 321 | + uint32_t nL0LoopNum = Arch35MmadOpt::LoopNum(embed, L0_TILE_N); | ||
| 322 | + uint32_t kL0LoopNum = Arch35MmadOpt::LoopNum(curBaseTileSize, L0_TILE_K); | ||
| 323 | + uint32_t mFixPAligned8 = Arch35MmadOpt::AlignUpPow2<8>(rowNum); | ||
| 324 | + // while splitting the base tile OTmp to 2 AIVs, | ||
| 325 | + // the order of the elements in each column is expected to be preserved, | ||
| 326 | + // which means a column in l0C cannot be chunked and processed by dualMode FixPipe seperately. | ||
| 327 | + // therefore, FixPipe won't launch until each portion(chunked only by columns, based on nbuffer strategy) | ||
| 328 | + // of the base tile is ready on l0C | ||
| 329 | + uint32_t nLoopCounter = Arch35MmadOpt::GetCurLoopCounter(gatheredKvSTileIdx, nL0LoopNum); | ||
| 330 | + uint32_t nOffset = 0; | ||
| 331 | + for (uint32_t nL0Itr = 0; nL0Itr < Arch35MmadOpt::LoopBound<staticNL0LoopNum>(nL0LoopNum); nL0Itr++) { | ||
| 332 | + uint32_t l0TileNAct = (nL0Itr == nL0LoopNum - 1) ? (embed - nOffset) : L0_TILE_N; | ||
| 333 | + // l0C nbuffer chunked only in n loop | ||
| 334 | + uint32_t l0CLoopCounter = nLoopCounter; | ||
| 335 | + uint32_t l0CBufId = Arch35MmadOpt::StageId<L0_STAGES>(l0CLoopCounter); | ||
| 336 | + // uint32_t l0CEventId = l0CBufId; | ||
| 337 | + uint32_t l0CEventId = l0CBufId + 2; | ||
| 338 | + auto l0CLayoutTla = tla::MakeLayoutL0C(rowNum, l0TileNAct); | ||
| 339 | + auto l0CTensorTla = tla::MakeTensor(l0CTensor[l0CBufId], l0CLayoutTla, Arch::PositionL0C{}); | ||
| 340 | + uint32_t mOffset = 0; | ||
| 341 | + uint32_t l0ALoopBase = static_cast<uint32_t>(prefixSumL0AStages); | ||
| 342 | + uint32_t l0BLoopBase = static_cast<uint32_t>(prefixSumL0BStages) + nL0Itr * kL0LoopNum; | ||
| 343 | + for (uint32_t mL0Itr = 0; mL0Itr < Arch35MmadOpt::LoopBound<staticML0LoopNum>(mL0LoopNum); mL0Itr++) { | ||
| 344 | + uint32_t l0TileMAct = (mL0Itr == mL0LoopNum - 1) ? (rowNum - mOffset) : L0_TILE_M; | ||
| 345 | + // uint32_t mLoopCounter = GetCurLoopCounter(gatheredKvSTileIdx, mL0LoopNum, mL0Itr); | ||
| 346 | + // different m chunks will be concated in the same piece of l0C buffer | ||
| 347 | + auto l0CTensorTlaTile = GetTile(l0CTensorTla, | ||
| 348 | + tla::MakeCoord(mOffset, 0), tla::MakeShape(l0TileMAct, l0TileNAct)); | ||
| 349 | + uint32_t l0ALoopCounter = l0ALoopBase; | ||
| 350 | + uint32_t l0BLoopCounter = l0BLoopBase; | ||
| 351 | + uint32_t kOffset = 0; | ||
| 352 | + for (uint32_t kL0Itr = 0; kL0Itr < kL0LoopNum; kL0Itr++) { | ||
| 353 | + uint32_t l0TileKAct = (kL0Itr == kL0LoopNum - 1) ? | ||
| 354 | + (curBaseTileSize - kOffset) : L0_TILE_K; | ||
| 355 | + uint32_t l0ABufId = Arch35MmadOpt::StageId<L0_STAGES>(l0ALoopCounter); | ||
| 356 | + // l0ABufId = (mLoopCounter % 2 == 0) ? (1 - l0ABufId) : l0ABufId; | ||
| 357 | + uint32_t l0BBufId = Arch35MmadOpt::StageId<L0_STAGES>(l0BLoopCounter); | ||
| 358 | + uint32_t l0AEventId = l0ABufId; | ||
| 359 | + uint32_t l0BEventId = l0BBufId + 2; | ||
| 360 | + // when L0B buffers wouldn't be reused across the k loop | ||
| 361 | + // redundant L0B load caused by m loop can be avoided | ||
| 362 | + auto l1BTensorTlaTile = GetTile(l1BTensorTla, | ||
| 363 | + tla::MakeCoord(kOffset, nOffset), tla::MakeShape(l0TileKAct, l0TileNAct)); | ||
| 364 | + auto l0BLayoutTla = tla::MakeLayout<ElementB, LayoutTagL0B>(l0TileKAct, l0TileNAct); | ||
| 365 | + auto l0BTensorTla = tla::MakeTensor(l0BTensor[l0BBufId], l0BLayoutTla, Arch::PositionL0B{}); | ||
| 366 | + | ||
| 367 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0BEventId); | ||
| 368 | + copyL1ToL0B(l0BTensorTla, l1BTensorTlaTile); | ||
| 369 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(l0BEventId); | ||
| 370 | + | ||
| 371 | + if ((mL0Itr == mL0LoopNum - 1) && (nL0Itr == nL0LoopNum - 1) && (kL0Itr == kL0LoopNum - 1)) { | ||
| 372 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(l1BEventId); | ||
| 373 | + } | ||
| 374 | + | ||
| 375 | + auto l1ATensorTlaTile = GetTile(l1ATensorTla, | ||
| 376 | + tla::MakeCoord(mOffset, kOffset), tla::MakeShape(l0TileMAct, l0TileKAct)); | ||
| 377 | + auto l0ALayoutTla = tla::MakeLayout<ElementA, LayoutTagL0A>(l0TileMAct, l0TileKAct); | ||
| 378 | + auto l0ATensorTla = tla::MakeTensor(l0ATensor[l0ABufId], l0ALayoutTla, Arch::PositionL0A{}); | ||
| 379 | + | ||
| 380 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0AEventId); | ||
| 381 | + copyL1ToL0A(l0ATensorTla, l1ATensorTlaTile); | ||
| 382 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(l0AEventId); | ||
| 383 | + // reverse crossCoreSync for P | ||
| 384 | + if ((mL0Itr == mL0LoopNum - 1) && (nL0Itr == nL0LoopNum - 1) && (kL0Itr == kL0LoopNum - 1)) { | ||
| 385 | + SetCrossCoreSync<4, PIPE_MTE1>(smToMm2Flag); | ||
| 386 | + } | ||
| 387 | + | ||
| 388 | + bool initMmad = (kL0Itr == 0); | ||
| 389 | + uint32_t l0TileMAligned = Arch35MmadOpt::AlignUpPow2<16>(l0TileMAct); | ||
| 390 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(l0AEventId); | ||
| 391 | + | ||
| 392 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(l0BEventId); | ||
| 393 | + | ||
| 394 | + if (mL0Itr == 0 && kL0Itr == 0) { | ||
| 395 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(l0CEventId); | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + tileMmad( | ||
| 399 | + l0CTensorTlaTile, | ||
| 400 | + l0ATensorTla, | ||
| 401 | + l0BTensorTla, | ||
| 402 | + l0TileMAligned, | ||
| 403 | + l0TileNAct, | ||
| 404 | + l0TileKAct, | ||
| 405 | + initMmad); | ||
| 406 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0AEventId); | ||
| 407 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0BEventId); | ||
| 408 | + l0ALoopCounter++; | ||
| 409 | + l0BLoopCounter++; | ||
| 410 | + kOffset += L0_TILE_K; | ||
| 411 | + } | ||
| 412 | + mOffset += L0_TILE_M; | ||
| 413 | + l0ALoopBase += kL0LoopNum; | ||
| 414 | + } | ||
| 415 | + // fixpipe | ||
| 416 | + if (nL0Itr == 0) { | ||
| 417 | + // reverse crossCoreSync, do fixPipe only after ubCTensor is fully released | ||
| 418 | + WaitCrossCoreSync<4, PIPE_FIX>(mm2ToReFlag); | ||
| 419 | + } | ||
| 420 | + AscendC::SetFlag<AscendC::HardEvent::M_FIX>(l0CEventId); | ||
| 421 | + AscendC::WaitFlag<AscendC::HardEvent::M_FIX>(l0CEventId); | ||
| 422 | + // 需要kernel传输ubCTensor的时候确保其shape的m,n是满足32B(8个32位元素)对齐的 | ||
| 423 | + // rounded up by 8 and splited in half to each AIV | ||
| 424 | + // valid rows in AIV0: [0, mFixPAligned8 / 2 - 1] | ||
| 425 | + // valid rows in AIV1: [mFixPAligned8 / 2, rowNum - 1] | ||
| 426 | + uint32_t nFixPAligned8 = Arch35MmadOpt::AlignUpPow2<8>(l0TileNAct); | ||
| 427 | + auto ubCTensorTlaTile = GetTile(ubCTensor, | ||
| 428 | + tla::MakeCoord(0, nOffset), tla::MakeShape(mFixPAligned8, nFixPAligned8)); | ||
| 429 | + copyL0CToDst(ubCTensorTlaTile, l0CTensorTla); | ||
| 430 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(l0CEventId); | ||
| 431 | + nLoopCounter++; | ||
| 432 | + nOffset += L0_TILE_N; | ||
| 433 | + } | ||
| 434 | + // crossCoreSync after all fixPipe move | ||
| 435 | + SetCrossCoreSync<4, PIPE_FIX>(mm2ToReFlag); | ||
| 436 | + } | ||
| 437 | + | ||
| 438 | +protected: | ||
| 439 | + /// Data members | ||
| 440 | + AscendC::LocalTensor<ElementA> l1ATensor[MAX_L1_STAGES]; | ||
| 441 | + AscendC::LocalTensor<ElementB> l1BTensor[MAX_L1_STAGES]; | ||
| 442 | + AscendC::LocalTensor<uint64_t> l1VSDBTensor[VSDB_BUF_NUM]; | ||
| 443 | + AscendC::LocalTensor<ElementA> l0ATensor[L0_STAGES]; | ||
| 444 | + AscendC::LocalTensor<ElementB> l0BTensor[L0_STAGES]; | ||
| 445 | + AscendC::LocalTensor<ElementAccumulator> l0CTensor[L0_STAGES]; | ||
| 446 | + | ||
| 447 | + TileMmad tileMmad; | ||
| 448 | + CopyL1ToL0A copyL1ToL0A; | ||
| 449 | + CopyL1ToL0B copyL1ToL0B; | ||
| 450 | + | ||
| 451 | + uint32_t l1ATileM; | ||
| 452 | + uint32_t l1BTileN; | ||
| 453 | + uint32_t l1ATileK; | ||
| 454 | + uint32_t l1BTileK; | ||
| 455 | + uint32_t l1ABufNum; | ||
| 456 | + uint32_t l1BBufNum; | ||
| 457 | + uint32_t l1VSdbSel = 0; | ||
| 458 | +}; | ||
| 459 | +//////////////////////////////////////////////////////////////////// | ||
| 460 | + | ||
| 461 | +} // namespace NpuArch::Gemm::Block | ||
| 462 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/gemm/block/block_mmad_qk.hpp+323-0
| @@ -0,0 +1,323 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +//////////////////////////////////////////////////////////////////// | ||
| 24 | + | ||
| 25 | +namespace NpuArch::Gemm::Block { | ||
| 26 | +//////////////////////////////////////////////////////////////////// | ||
| 27 | + | ||
| 28 | +template < | ||
| 29 | + bool PAGED_CACHE_FLAG_, | ||
| 30 | + bool ENABLE_UNIT_FLAG_, | ||
| 31 | + class L1TileShape_, | ||
| 32 | + class L0TileShape_, | ||
| 33 | + class AType_, | ||
| 34 | + class BType_, | ||
| 35 | + class CType_, | ||
| 36 | + class BiasType_, | ||
| 37 | + class TileCopy_, | ||
| 38 | + class TileMmad_> | ||
| 39 | +struct BlockMmad< | ||
| 40 | + MmadAtlasA2SFAIQK<PAGED_CACHE_FLAG_, ENABLE_UNIT_FLAG_>, | ||
| 41 | + L1TileShape_, | ||
| 42 | + L0TileShape_, | ||
| 43 | + AType_, | ||
| 44 | + BType_, | ||
| 45 | + CType_, | ||
| 46 | + BiasType_, | ||
| 47 | + TileCopy_, | ||
| 48 | + TileMmad_> { | ||
| 49 | +public: | ||
| 50 | + using DispatchPolicy = MmadAtlasA2SFAIQK<PAGED_CACHE_FLAG_, ENABLE_UNIT_FLAG_>; | ||
| 51 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 52 | + | ||
| 53 | + using L1TileShape = L1TileShape_; | ||
| 54 | + using L0TileShape = L0TileShape_; | ||
| 55 | + | ||
| 56 | + using ElementA = typename AType_::Element; | ||
| 57 | + using LayoutA = typename AType_::Layout; | ||
| 58 | + using ElementB = typename BType_::Element; | ||
| 59 | + using LayoutB = typename BType_::Layout; | ||
| 60 | + using ElementC = typename CType_::Element; | ||
| 61 | + using LayoutC = typename CType_::Layout; | ||
| 62 | + | ||
| 63 | + using TileMmad = TileMmad_; | ||
| 64 | + using CopyGmToL1A = typename TileCopy_::CopyGmToL1A; | ||
| 65 | + using CopyGmToL1B = typename TileCopy_::CopyGmToL1B; | ||
| 66 | + using CopyL1ToL0A = typename TileCopy_::CopyL1ToL0A; | ||
| 67 | + using CopyL1ToL0B = typename TileCopy_::CopyL1ToL0B; | ||
| 68 | + using CopyL0CToGm = typename TileCopy_::CopyL0CToGm; | ||
| 69 | + | ||
| 70 | + using ElementAccumulator = | ||
| 71 | + typename Gemm::helper::ElementAccumulatorSelector<ElementA, ElementB>::ElementAccumulator; | ||
| 72 | + | ||
| 73 | + using LayoutAInL1 = typename CopyL1ToL0A::LayoutSrc; | ||
| 74 | + using LayoutBInL1 = typename CopyL1ToL0B::LayoutSrc; | ||
| 75 | + using LayoutAInL0 = typename CopyL1ToL0A::LayoutDst; | ||
| 76 | + using LayoutBInL0 = typename CopyL1ToL0B::LayoutDst; | ||
| 77 | + using LayoutCInL0 = layout::zN; | ||
| 78 | + | ||
| 79 | + using L1AAlignHelper = Gemm::helper::L1AlignHelper<ElementA, LayoutA>; | ||
| 80 | + using L1BAlignHelper = Gemm::helper::L1AlignHelper<ElementB, LayoutB>; | ||
| 81 | + | ||
| 82 | + static constexpr uint32_t STAGES = DispatchPolicy::STAGES; | ||
| 83 | + | ||
| 84 | + static constexpr uint32_t L1A_SIZE = L1TileShape::M * L1TileShape::K * sizeof(ElementA); | ||
| 85 | + static constexpr uint32_t L1B_SIZE = L1TileShape::N * L1TileShape::K * sizeof(ElementB); | ||
| 86 | + | ||
| 87 | + static constexpr uint32_t L0A_SIZE = ArchTag::L0A_SIZE; | ||
| 88 | + static constexpr uint32_t L0B_SIZE = ArchTag::L0B_SIZE; | ||
| 89 | + static constexpr uint32_t L0C_SIZE = ArchTag::L0C_SIZE; | ||
| 90 | + | ||
| 91 | + static constexpr uint32_t L0A_PINGPONG_BUF_SIZE = L0A_SIZE / STAGES; | ||
| 92 | + static constexpr uint32_t L0B_PINGPONG_BUF_SIZE = L0B_SIZE / STAGES; | ||
| 93 | + static constexpr uint32_t L0C_PINGPONG_BUF_SIZE = L0C_SIZE / STAGES; | ||
| 94 | + | ||
| 95 | + static constexpr uint32_t BLOCK_SIZE = 16; | ||
| 96 | + | ||
| 97 | + static_assert(std::is_same_v<LayoutC, layout::RowMajor>, "LayoutC only support RowMajor yet!"); | ||
| 98 | + | ||
| 99 | + __aicore__ inline | ||
| 100 | + BlockMmad(Arch::Resource<ArchTag> &resource, uint32_t l1BufAddrStart = 0) | ||
| 101 | + { | ||
| 102 | + l1ATensor = resource.l1Buf.template GetBufferByByte<ElementA>(l1BufAddrStart); | ||
| 103 | + | ||
| 104 | + for (uint32_t i = 0; i < STAGES; i++) { | ||
| 105 | + l1BTensor[i] = resource.l1Buf.template GetBufferByByte<ElementB>(l1BufAddrStart + L1A_SIZE + L1B_SIZE * i); | ||
| 106 | + | ||
| 107 | + l0ATensor[i] = resource.l0ABuf.template GetBufferByByte<ElementA>(L0A_PINGPONG_BUF_SIZE * i); | ||
| 108 | + l0BTensor[i] = resource.l0BBuf.template GetBufferByByte<ElementB>(L0B_PINGPONG_BUF_SIZE * i); | ||
| 109 | + l0CTensor[i] = resource.l0CBuf.template GetBufferByByte<ElementAccumulator>(L0C_PINGPONG_BUF_SIZE * i); | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + __aicore__ inline | ||
| 114 | + ~BlockMmad() {} | ||
| 115 | + | ||
| 116 | + __aicore__ inline | ||
| 117 | + void loadQGM(AscendC::GlobalTensor<ElementA> gA, LayoutA layoutA, uint32_t rowNum, uint32_t &singleGroupHeads, | ||
| 118 | + uint64_t qStride) | ||
| 119 | + { | ||
| 120 | + uint32_t embed = layoutA.shape(1); | ||
| 121 | + uint32_t rowNumRound = RoundUp<L1AAlignHelper::M_ALIGNED>(rowNum); | ||
| 122 | + uint32_t tokenNumPerGroup = rowNum / singleGroupHeads; | ||
| 123 | + | ||
| 124 | + auto layoutSingleANd = layoutA.GetTileLayout(MakeCoord(singleGroupHeads, embed)); | ||
| 125 | + | ||
| 126 | + LayoutAInL1 layoutAInL1 = LayoutAInL1::template MakeLayout<ElementA>(rowNum, embed); | ||
| 127 | + | ||
| 128 | + copyGmToL1A(l1ATensor, | ||
| 129 | + gA, | ||
| 130 | + layoutAInL1, | ||
| 131 | + layoutSingleANd, | ||
| 132 | + tokenNumPerGroup, | ||
| 133 | + qStride, | ||
| 134 | + tokenNumPerGroup, | ||
| 135 | + BLOCK_SIZE, | ||
| 136 | + rowNumRound); | ||
| 137 | + | ||
| 138 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(EVENT_ID3); | ||
| 139 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(EVENT_ID3); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + __aicore__ inline | ||
| 143 | + void getBlockShape(GemmCoord &actualShape, uint32_t nL1Idx, uint32_t nL1Loop, uint32_t stackSeqTile) | ||
| 144 | + { | ||
| 145 | + uint32_t nSplitSize = L1TileShape::N; | ||
| 146 | + if (nL1Idx == nL1Loop - 1) { | ||
| 147 | + nSplitSize = stackSeqTile - nL1Idx * L1TileShape::N; | ||
| 148 | + } | ||
| 149 | + actualShape[1] = nSplitSize; | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + __aicore__ inline | ||
| 153 | + void operator()(AscendC::GlobalTensor<ElementA> gA, | ||
| 154 | + AscendC::GlobalTensor<ElementB> gB, | ||
| 155 | + AscendC::GlobalTensor<ElementC> gC, | ||
| 156 | + AscendC::GlobalTensor<int32_t> gBlockTable, | ||
| 157 | + AscendC::GlobalTensor<int32_t> gSelectIdx, | ||
| 158 | + LayoutA layoutA, LayoutB layoutB, LayoutC layoutC, GemmCoord actualOriShape, | ||
| 159 | + uint32_t &nIdx, uint32_t &nLoop, uint32_t &blockSize, uint32_t strideKV, | ||
| 160 | + uint32_t &y, uint32_t &selectNum, uint32_t &kvYBlockNum, uint32_t &kvSeqlen) | ||
| 161 | + { | ||
| 162 | + uint32_t rowNum = actualOriShape[0]; | ||
| 163 | + uint32_t stackSeqTile = actualOriShape[1]; | ||
| 164 | + uint32_t embed = actualOriShape[2]; | ||
| 165 | + | ||
| 166 | + GemmCoord actualShape{rowNum, 0, embed}; | ||
| 167 | + GemmCoord actualNextShape{rowNum, 0, embed}; | ||
| 168 | + | ||
| 169 | + uint32_t gBOffset = 0; | ||
| 170 | + uint32_t gBNextOffset = 0; | ||
| 171 | + | ||
| 172 | + LayoutAInL1 layoutAInL1 = LayoutAInL1::template MakeLayout<ElementA>(rowNum, embed); | ||
| 173 | + | ||
| 174 | + uint32_t tileNNumPerPaged = blockSize / L1TileShape::N; | ||
| 175 | + uint32_t nL1Loop = CeilDiv<L1TileShape::N>(stackSeqTile); | ||
| 176 | + | ||
| 177 | + for (uint32_t nL1Idx = 0; nL1Idx < nL1Loop; ++nL1Idx) { | ||
| 178 | + uint32_t nowNIdx = nIdx + nL1Idx / tileNNumPerPaged; | ||
| 179 | + | ||
| 180 | + getBlockShape(actualShape, nL1Idx, nL1Loop, stackSeqTile); | ||
| 181 | + | ||
| 182 | + uint32_t mActual = actualShape.m(); | ||
| 183 | + uint32_t kActual = actualShape.k(); | ||
| 184 | + uint32_t nActual = actualShape.n(); | ||
| 185 | + uint32_t mRound = RoundUp<L1AAlignHelper::M_ALIGNED>(mActual); | ||
| 186 | + | ||
| 187 | + LayoutBInL1 layoutBInL1 = LayoutBInL1::template MakeLayout<ElementB>(kActual, nActual); | ||
| 188 | + | ||
| 189 | + uint32_t processSize = 0; | ||
| 190 | + uint32_t nBlockOffset = nowNIdx * blockSize; | ||
| 191 | + uint32_t currentSelectYIdx = nBlockOffset / y; | ||
| 192 | + uint32_t currentYoffset = nBlockOffset % y; | ||
| 193 | + | ||
| 194 | + uint32_t currentYIdx = gSelectIdx.GetValue(currentSelectYIdx); | ||
| 195 | + uint32_t offsetInKV = currentYIdx * y + currentYoffset; | ||
| 196 | + | ||
| 197 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1KvPingPongFlag); | ||
| 198 | + | ||
| 199 | + while (processSize < nActual && currentSelectYIdx < selectNum && currentYIdx < kvYBlockNum && offsetInKV < kvSeqlen) { | ||
| 200 | + uint32_t yAcutal = (currentSelectYIdx == selectNum - 1 && currentYIdx == kvYBlockNum - 1 && kvSeqlen % y != 0) ? | ||
| 201 | + (kvSeqlen - y * currentYIdx) : y; | ||
| 202 | + uint32_t remainingInYBlock = yAcutal - currentYoffset; | ||
| 203 | + uint32_t remainingInNBlock = nActual - processSize; | ||
| 204 | + | ||
| 205 | + uint32_t actualYSize = min(remainingInNBlock, remainingInYBlock); | ||
| 206 | + if (actualYSize == 0) { | ||
| 207 | + break; | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + auto layoutBTile = layoutB.GetTileLayout(MakeCoord(kActual, actualYSize)); | ||
| 211 | + | ||
| 212 | + copyGmToL1B(l1BTensor[l1KvPingPongFlag][processSize], gB[offsetInKV * strideKV], layoutBInL1, layoutBTile); | ||
| 213 | + | ||
| 214 | + processSize += actualYSize; | ||
| 215 | + currentYoffset += actualYSize; | ||
| 216 | + offsetInKV += actualYSize; | ||
| 217 | + | ||
| 218 | + if (currentYoffset >= yAcutal) { | ||
| 219 | + currentSelectYIdx++; | ||
| 220 | + if (currentSelectYIdx >= selectNum) { | ||
| 221 | + break; | ||
| 222 | + } | ||
| 223 | + currentYoffset = 0; | ||
| 224 | + currentYIdx = gSelectIdx.GetValue(currentSelectYIdx); | ||
| 225 | + offsetInKV = currentYIdx * y; | ||
| 226 | + } | ||
| 227 | + } | ||
| 228 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1KvPingPongFlag); | ||
| 229 | + | ||
| 230 | + uint32_t mL0Loop = CeilDiv<L0TileShape::M>(mActual); | ||
| 231 | + uint32_t kL0Loop = CeilDiv<L0TileShape::K>(kActual); | ||
| 232 | + | ||
| 233 | + for (uint32_t mL0Idx = 0; mL0Idx < mL0Loop; mL0Idx++) { | ||
| 234 | + uint32_t mL0Actual = (mL0Idx < mL0Loop - 1) ? L0TileShape::M : (mActual - mL0Idx * L0TileShape::M); | ||
| 235 | + | ||
| 236 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(l0CPingPongFlag); | ||
| 237 | + | ||
| 238 | + for (uint32_t kL0Idx = 0; kL0Idx < kL0Loop; kL0Idx++) { | ||
| 239 | + uint32_t kL0Actual = (kL0Idx < kL0Loop - 1) ? L0TileShape::K : (kActual - kL0Idx * L0TileShape::K); | ||
| 240 | + | ||
| 241 | + LayoutAInL0 layoutAInL0 = LayoutAInL0::template MakeLayout<ElementA>(mL0Actual, kL0Actual); | ||
| 242 | + MatrixCoord l1ATileCoord{mL0Idx * L0TileShape::M, kL0Idx * L0TileShape::K}; | ||
| 243 | + auto l1ATile = l1ATensor[layoutAInL1.GetOffset(l1ATileCoord)]; | ||
| 244 | + | ||
| 245 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0ABPingPongFlag); | ||
| 246 | + copyL1ToL0A(l0ATensor[l0ABPingPongFlag], l1ATile, layoutAInL0, layoutAInL1); | ||
| 247 | + | ||
| 248 | + LayoutBInL0 layoutBInL0 = LayoutBInL0::template MakeLayout<ElementB>(kL0Actual, nActual); | ||
| 249 | + MatrixCoord l1BTileCoord{kL0Idx * L0TileShape::K, 0}; | ||
| 250 | + auto l1BTile = l1BTensor[l1KvPingPongFlag][layoutBInL1.GetOffset(l1BTileCoord)]; | ||
| 251 | + | ||
| 252 | + if ((mL0Idx == 0) && (kL0Idx == 0)) { | ||
| 253 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1KvPingPongFlag); | ||
| 254 | + } | ||
| 255 | + | ||
| 256 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0ABPingPongFlag + 2); | ||
| 257 | + copyL1ToL0B(l0BTensor[l0ABPingPongFlag], l1BTile, layoutBInL0, layoutBInL1); | ||
| 258 | + | ||
| 259 | + if ((mL0Idx == mL0Loop - 1) && (kL0Idx == kL0Loop - 1)) { | ||
| 260 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(l1KvPingPongFlag); | ||
| 261 | + } | ||
| 262 | + | ||
| 263 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(EVENT_ID0); | ||
| 264 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(EVENT_ID0); | ||
| 265 | + | ||
| 266 | + bool initMmad = kL0Idx == 0; | ||
| 267 | + tileMmad(l0CTensor[l0CPingPongFlag], | ||
| 268 | + l0ATensor[l0ABPingPongFlag], | ||
| 269 | + l0BTensor[l0ABPingPongFlag], | ||
| 270 | + mRound, | ||
| 271 | + nActual, | ||
| 272 | + kL0Actual, | ||
| 273 | + initMmad); | ||
| 274 | + | ||
| 275 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0ABPingPongFlag); | ||
| 276 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0ABPingPongFlag + 2); | ||
| 277 | + | ||
| 278 | + l0ABPingPongFlag = 1 - l0ABPingPongFlag; | ||
| 279 | + } | ||
| 280 | + AscendC::SetFlag<AscendC::HardEvent::M_FIX>(EVENT_ID0); | ||
| 281 | + AscendC::WaitFlag<AscendC::HardEvent::M_FIX>(EVENT_ID0); | ||
| 282 | + | ||
| 283 | + MatrixCoord gmCTileCoord{mL0Idx * L0TileShape::M, nL1Idx * L1TileShape::N}; | ||
| 284 | + LayoutC layoutCTile = layoutC.GetTileLayout(MakeCoord(mL0Actual, nActual)); | ||
| 285 | + auto layoutInL0C = LayoutCInL0::MakeLayoutInL0C(MakeCoord(mL0Actual, nActual)); | ||
| 286 | + | ||
| 287 | + copyL0CToGm(gC[layoutC.GetOffset(gmCTileCoord)], l0CTensor[l0CPingPongFlag], layoutCTile, layoutInL0C); | ||
| 288 | + | ||
| 289 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(l0CPingPongFlag); | ||
| 290 | + l0CPingPongFlag = 1 - l0CPingPongFlag; | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + l1KvPingPongFlag = 1 - l1KvPingPongFlag; | ||
| 294 | + } | ||
| 295 | + } | ||
| 296 | + | ||
| 297 | +protected: | ||
| 298 | + AscendC::LocalTensor<ElementA> l1ATensor; | ||
| 299 | + AscendC::LocalTensor<ElementB> l1BTensor[STAGES]; | ||
| 300 | + | ||
| 301 | + AscendC::LocalTensor<ElementA> l0ATensor[STAGES]; | ||
| 302 | + AscendC::LocalTensor<ElementB> l0BTensor[STAGES]; | ||
| 303 | + AscendC::LocalTensor<ElementAccumulator> l0CTensor[STAGES]; | ||
| 304 | + | ||
| 305 | + TileMmad tileMmad; | ||
| 306 | + CopyGmToL1A copyGmToL1A; | ||
| 307 | + CopyGmToL1B copyGmToL1B; | ||
| 308 | + CopyL1ToL0A copyL1ToL0A; | ||
| 309 | + CopyL1ToL0B copyL1ToL0B; | ||
| 310 | + CopyL0CToGm copyL0CToGm; | ||
| 311 | + | ||
| 312 | + uint32_t l1KvPingPongFlag = 0; | ||
| 313 | + uint32_t l0CPingPongFlag = 0; | ||
| 314 | + uint32_t l0ABPingPongFlag = 0; | ||
| 315 | +}; | ||
| 316 | + | ||
| 317 | +//////////////////////////////////////////////////////////////////// | ||
| 318 | + | ||
| 319 | +} // namespace NpuArch::Gemm::Block | ||
| 320 | + | ||
| 321 | + | ||
| 322 | + | ||
| 323 | + | ||
| @@ -0,0 +1,499 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @brief matmul implementation for single q&k^t base tile | ||
| 13 | + * This implementation is designed for the following senario: | ||
| 14 | + * A full q base tile is loaded to L1 from GM at the very beginning, | ||
| 15 | + * and it remains persistent until each k base tile is dealt | ||
| 16 | + * A full q*k^t base tile is loaded to UB from l0C, no workspace transit | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | +//////////////////////////////////////////////////////////////////// | ||
| 35 | + | ||
| 36 | +namespace NpuArch::Gemm::Block { | ||
| 37 | +//////////////////////////////////////////////////////////////////// | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + | ||
| 42 | +template <class T> | ||
| 43 | +struct HasParams { | ||
| 44 | + template <class U> | ||
| 45 | + static char test(typename U::Params*); | ||
| 46 | + template <class U> | ||
| 47 | + static int test(...); | ||
| 48 | + static constexpr bool value = sizeof(test<T>(0)) == sizeof(char); | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +struct Mm1L1TileHelper { | ||
| 52 | + uint32_t mm1L1TileM; | ||
| 53 | + uint32_t mm1L1TileN; | ||
| 54 | + uint32_t mm1L1TileKLeft; | ||
| 55 | + uint32_t mm1L1TileKRight; | ||
| 56 | + uint32_t qL1BufNum; | ||
| 57 | + uint32_t kL1BufNum; | ||
| 58 | + | ||
| 59 | + __aicore__ inline | ||
| 60 | + Mm1L1TileHelper() {} | ||
| 61 | + | ||
| 62 | + __aicore__ inline | ||
| 63 | + Mm1L1TileHelper( | ||
| 64 | + uint32_t m, | ||
| 65 | + uint32_t n, | ||
| 66 | + uint32_t kl, | ||
| 67 | + uint32_t kr, | ||
| 68 | + uint32_t pbn, | ||
| 69 | + uint32_t vbn) : | ||
| 70 | + mm1L1TileM(m), | ||
| 71 | + mm1L1TileN(n), | ||
| 72 | + mm1L1TileKLeft(kl), | ||
| 73 | + mm1L1TileKRight(kr), | ||
| 74 | + qL1BufNum(pbn), | ||
| 75 | + kL1BufNum(vbn) {} | ||
| 76 | +}; | ||
| 77 | + | ||
| 78 | + | ||
| 79 | +template < | ||
| 80 | + class L1TileShape_, | ||
| 81 | + class L0TileShape_, | ||
| 82 | + class ElementA_, | ||
| 83 | + class ElementB_, | ||
| 84 | + class ElementC_, | ||
| 85 | + class ElementBias_, | ||
| 86 | + class TileCopy_, | ||
| 87 | + class TileMmad_> | ||
| 88 | +struct BlockMmadTla< | ||
| 89 | + MmadAtlasA5BsaQK, | ||
| 90 | + L1TileShape_, | ||
| 91 | + L0TileShape_, | ||
| 92 | + ElementA_, | ||
| 93 | + ElementB_, | ||
| 94 | + ElementC_, | ||
| 95 | + ElementBias_, | ||
| 96 | + TileCopy_, | ||
| 97 | + TileMmad_> | ||
| 98 | +{ | ||
| 99 | +public: | ||
| 100 | + using DispatchPolicy = MmadAtlasA5BsaQK; | ||
| 101 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 102 | + using TileCopy = TileCopy_; | ||
| 103 | + using ElementA = ElementA_; | ||
| 104 | + using ElementB = ElementB_; | ||
| 105 | + using ElementC = ElementC_; | ||
| 106 | + | ||
| 107 | + using TileMmad = TileMmad_; | ||
| 108 | + | ||
| 109 | + using CopyL1ToL0A = typename TileCopy::CopyL1ToL0A; | ||
| 110 | + using CopyL1ToL0B = typename TileCopy::CopyL1ToL0B; | ||
| 111 | + | ||
| 112 | + using ElementAccumulator = typename TileCopy::ElementAccumulator; | ||
| 113 | + | ||
| 114 | + using LayoutTagL1A = typename TileCopy::LayoutTagL1A; | ||
| 115 | + using LayoutTagL1B = typename TileCopy::LayoutTagL1B; | ||
| 116 | + using LayoutTagL0A = typename TileCopy::LayoutTagL0A; | ||
| 117 | + using LayoutTagL0B = typename TileCopy::LayoutTagL0B; | ||
| 118 | + | ||
| 119 | + static constexpr uint32_t L0_STAGES = DispatchPolicy::L0_STAGES; | ||
| 120 | + static constexpr uint32_t L0_TILE_M = tla::get<0>(L0TileShape_{}); | ||
| 121 | + static constexpr uint32_t L0_TILE_N = tla::get<1>(L0TileShape_{}); | ||
| 122 | + static constexpr uint32_t L0_TILE_K = tla::get<2>(L0TileShape_{}); | ||
| 123 | + static constexpr uint32_t L0A_PINGPONG_BUF_SIZE = ArchTag::L0A_SIZE / L0_STAGES; | ||
| 124 | + static constexpr uint32_t L0B_PINGPONG_BUF_SIZE = ArchTag::L0B_SIZE / L0_STAGES; | ||
| 125 | + static constexpr uint32_t L0C_HALF_BUF_SIZE = ArchTag::L0C_SIZE / 2; | ||
| 126 | + static constexpr uint32_t L0C_PINGPONG_BUF_SIZE = L0C_HALF_BUF_SIZE / L0_STAGES; | ||
| 127 | + | ||
| 128 | + static constexpr uint32_t MAX_L1_STAGES = 3; // 编译期常量,为静态L1Tensor数组开辟准备。取一个buffer份数的极大值 | ||
| 129 | + static constexpr uint32_t V0_V1_FLAG_ID_OFFSET = 16; // 核间同步mode4,AIC侧需要两个flagId分别对应两个AIV | ||
| 130 | + | ||
| 131 | + __aicore__ inline | ||
| 132 | + BlockMmadTla(Arch::Resource<ArchTag> &resource, Mm1L1TileHelper &mm1L1TileHelper) | ||
| 133 | + { | ||
| 134 | + l1ATileM = mm1L1TileHelper.mm1L1TileM; | ||
| 135 | + l1BTileN = mm1L1TileHelper.mm1L1TileN; | ||
| 136 | + l1ATileK = mm1L1TileHelper.mm1L1TileKLeft; | ||
| 137 | + l1BTileK = mm1L1TileHelper.mm1L1TileKRight; | ||
| 138 | + l1ABufNum = mm1L1TileHelper.qL1BufNum; | ||
| 139 | + l1BBufNum = mm1L1TileHelper.kL1BufNum; | ||
| 140 | + | ||
| 141 | + for (uint32_t i = 0; i < l1ABufNum; i++) { | ||
| 142 | + l1ATensor[i] = resource.l1Buf.template GetBufferByByte<ElementA>( | ||
| 143 | + l1ATileM * l1ATileK * sizeof(ElementA) * i); | ||
| 144 | + } | ||
| 145 | + for (uint32_t i = 0; i < l1BBufNum; i++) { | ||
| 146 | + l1BTensor[i] = resource.l1Buf.template GetBufferByByte<ElementB>( | ||
| 147 | + l1ATileM * l1ATileK * sizeof(ElementA) * l1ABufNum + | ||
| 148 | + l1BTileK * l1BTileN * sizeof(ElementB) * i); | ||
| 149 | + } | ||
| 150 | + for (uint32_t i = 0; i < L0_STAGES; i++) { | ||
| 151 | + l0ATensor[i] = resource.l0ABuf.template GetBufferByByte<ElementA>( | ||
| 152 | + L0A_PINGPONG_BUF_SIZE * i); | ||
| 153 | + l0BTensor[i] = resource.l0BBuf.template GetBufferByByte<ElementB>( | ||
| 154 | + L0B_PINGPONG_BUF_SIZE * i); | ||
| 155 | + l0CTensor[i] = resource.l0CBuf.template GetBufferByByte<ElementAccumulator>( | ||
| 156 | + L0C_PINGPONG_BUF_SIZE * i); | ||
| 157 | + } | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + /// Destructor | ||
| 161 | + __aicore__ inline | ||
| 162 | + ~BlockMmadTla() {} | ||
| 163 | + | ||
| 164 | + template <class TensorA> | ||
| 165 | + __aicore__ inline | ||
| 166 | + void loadQGM(TensorA &gATensor, GemmCoord actualOriShape) | ||
| 167 | + { | ||
| 168 | + using CopyGmToL1A = typename TileCopy_::template CopyGmToL1A<TensorA>; | ||
| 169 | + CopyGmToL1A copyGmToL1A; | ||
| 170 | + uint32_t rowNum = actualOriShape[0]; | ||
| 171 | + uint32_t embed = actualOriShape[1]; | ||
| 172 | + auto l1ALayoutTla = tla::MakeLayout<ElementA, LayoutTagL1A>(rowNum, embed); | ||
| 173 | + auto l1ATensorTla = tla::MakeTensor(l1ATensor[0], l1ALayoutTla, Arch::PositionL1{}); | ||
| 174 | + auto l1ATensorTlaTile = GetTile(l1ATensorTla, | ||
| 175 | + tla::MakeCoord(0, 0), tla::MakeShape(rowNum, embed)); | ||
| 176 | + auto gATensorTlaTile = GetTile(gATensor, | ||
| 177 | + tla::MakeCoord(0, 0), tla::MakeShape(rowNum, embed)); | ||
| 178 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 179 | + copyGmToL1A(l1ATensorTlaTile, gATensorTlaTile); | ||
| 180 | + | ||
| 181 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(EVENT_ID0); | ||
| 182 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(EVENT_ID0); | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 186 | + __aicore__ inline | ||
| 187 | + void SetCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 188 | + { | ||
| 189 | + // in mode 4, AIC set for 2 AIVs seperately | ||
| 190 | + if constexpr (MODE == 4U) { | ||
| 191 | + uint16_t flagIdV0 = crossCoreFlag.id; | ||
| 192 | + uint16_t flagIdV1 = flagIdV0 + V0_V1_FLAG_ID_OFFSET; | ||
| 193 | + Arch::CrossCoreFlag crossCoreFlagV1(flagIdV1); | ||
| 194 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlag); | ||
| 195 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlagV1); | ||
| 196 | + } | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 200 | + __aicore__ inline | ||
| 201 | + void WaitCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 202 | + { | ||
| 203 | + // in mode 4, AIC wait for 2 AIVs seperately | ||
| 204 | + if constexpr (MODE == 4U) { | ||
| 205 | + uint16_t flagIdV0 = crossCoreFlag.id; | ||
| 206 | + uint16_t flagIdV1 = flagIdV0 + V0_V1_FLAG_ID_OFFSET; | ||
| 207 | + Arch::CrossCoreFlag crossCoreFlagV1(flagIdV1); | ||
| 208 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlag); | ||
| 209 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlagV1); | ||
| 210 | + } | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + __aicore__ inline | ||
| 214 | + uint32_t GetCurLoopCounter(uint32_t outterLoopItr, uint32_t curLoopNum, uint32_t curLoopItr) | ||
| 215 | + { | ||
| 216 | + return outterLoopItr * curLoopNum + curLoopItr; | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + template <class TensorB, class TensorL1B> | ||
| 220 | + __aicore__ inline | ||
| 221 | + void SparseKL1TileNLoad(TensorB &gBTensor, TensorL1B &l1BTensorTla, | ||
| 222 | + AscendC::GlobalTensor<int32_t> gSparseBlockIdx, | ||
| 223 | + uint32_t gatheredKvSTileIdx, uint32_t kvSeqlen, | ||
| 224 | + uint32_t kvSBaseTile, uint32_t blockShapeY, | ||
| 225 | + uint32_t yBlockNumAval, uint32_t yBlockNumRsvd, | ||
| 226 | + uint32_t l1BTileNAct, uint32_t embed, | ||
| 227 | + uint32_t kvSBaseTileInnerOffset) | ||
| 228 | + { | ||
| 229 | + using CopyGmToL1B = typename TileCopy_::template CopyGmToL1B<TensorB>; | ||
| 230 | + CopyGmToL1B copyGmToL1B; | ||
| 231 | + uint32_t baseTileStartOffset = gatheredKvSTileIdx * kvSBaseTile + kvSBaseTileInnerOffset; | ||
| 232 | + uint32_t baseTileEndOffset = baseTileStartOffset + l1BTileNAct; | ||
| 233 | + // 稀疏情况下对实际选中的部分gather后进行基本块切分 | ||
| 234 | + // 当前处理的Yblock在gather的序列中的起始偏移,初始值为当前基块的起始偏移 | ||
| 235 | + uint32_t gatheredStartOffset = baseTileStartOffset; | ||
| 236 | + // 当前处理的Yblock gather后的下标,初始值为基本块起始偏移对应的按Y方向稀疏block的gather后起始下标 | ||
| 237 | + uint32_t gatheredYBlockIdx = gatheredStartOffset / blockShapeY; | ||
| 238 | + // 当前基本块起始偏移对应的按Y方向稀疏后的block内起始偏移 | ||
| 239 | + uint32_t yBlockInnerStartOffset = gatheredStartOffset % blockShapeY; | ||
| 240 | + // 当前处理的Yblock原始的下标,初始值为基本块对应的按Y方向稀疏block的原始起始下标 | ||
| 241 | + uint32_t oriYBlockIdx = gSparseBlockIdx.GetValue(gatheredYBlockIdx); | ||
| 242 | + // 当前处理的Yblock起始位置在原始序列中的偏移,初始值为基本块在原始序列中的起始偏移 | ||
| 243 | + uint32_t oriStartOffset = oriYBlockIdx * blockShapeY + yBlockInnerStartOffset; | ||
| 244 | + // 逐稀疏block搬移填充基本块过程中,已处理的累积序列长度 | ||
| 245 | + uint32_t dealtLenAccum = 0; | ||
| 246 | + | ||
| 247 | + while (dealtLenAccum < l1BTileNAct && gatheredYBlockIdx < yBlockNumRsvd && | ||
| 248 | + oriYBlockIdx < yBlockNumAval && oriStartOffset < kvSeqlen) { | ||
| 249 | + uint32_t curYBlockSize = blockShapeY; | ||
| 250 | + if (oriYBlockIdx == yBlockNumAval - 1) { | ||
| 251 | + curYBlockSize = kvSeqlen - oriYBlockIdx * blockShapeY; | ||
| 252 | + } | ||
| 253 | + uint32_t gatheredEndOffset = | ||
| 254 | + min(gatheredYBlockIdx * blockShapeY + curYBlockSize, | ||
| 255 | + baseTileEndOffset); | ||
| 256 | + // 当前循环处理的序列长度 | ||
| 257 | + uint32_t curDealtLen = gatheredEndOffset - gatheredStartOffset; | ||
| 258 | + if (curDealtLen == 0) { | ||
| 259 | + break; | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + auto l1BTensorTlaTile = GetTile(l1BTensorTla, | ||
| 263 | + tla::MakeCoord(0, dealtLenAccum), tla::MakeShape(embed, curDealtLen)); | ||
| 264 | + auto gBTensorTlaTile = GetTile(gBTensor, | ||
| 265 | + tla::MakeCoord(0, oriStartOffset), tla::MakeShape(embed, curDealtLen)); | ||
| 266 | + copyGmToL1B(l1BTensorTlaTile, gBTensorTlaTile); | ||
| 267 | + // 为下一次循环刷新循环变量 | ||
| 268 | + dealtLenAccum += curDealtLen; | ||
| 269 | + gatheredStartOffset += curDealtLen; | ||
| 270 | + gatheredYBlockIdx = gatheredStartOffset / blockShapeY; | ||
| 271 | + yBlockInnerStartOffset = gatheredStartOffset % blockShapeY; | ||
| 272 | + if (dealtLenAccum < l1BTileNAct) { | ||
| 273 | + oriYBlockIdx = gSparseBlockIdx.GetValue(gatheredYBlockIdx); | ||
| 274 | + oriStartOffset = oriYBlockIdx * blockShapeY + yBlockInnerStartOffset; | ||
| 275 | + } | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + template <class TensorB, class TensorC> | ||
| 280 | + __aicore__ inline | ||
| 281 | + void operator()(TensorB &gBTensor, TensorC &ubCTensor, | ||
| 282 | + AscendC::GlobalTensor<int32_t> gSparseBlockIdx, | ||
| 283 | + GemmCoord actualOriShape, | ||
| 284 | + uint32_t gatheredKvSTileIdx, uint32_t kvSeqlen, | ||
| 285 | + uint32_t kvSBaseTile, uint32_t blockShapeY, | ||
| 286 | + uint32_t yBlockNumAval, uint32_t yBlockNumRsvd, | ||
| 287 | + uint64_t prefixSumL0AStages, uint64_t prefixSumL0BStages, | ||
| 288 | + Arch::CrossCoreFlag mm1ToSmFlag, | ||
| 289 | + float scaleValue = 0.0f){ | ||
| 290 | + this->operator()<0>(gBTensor, ubCTensor, gSparseBlockIdx, | ||
| 291 | + actualOriShape, gatheredKvSTileIdx, kvSeqlen, | ||
| 292 | + kvSBaseTile, blockShapeY, yBlockNumAval, yBlockNumRsvd, | ||
| 293 | + prefixSumL0AStages, prefixSumL0BStages, | ||
| 294 | + mm1ToSmFlag, scaleValue); | ||
| 295 | + } | ||
| 296 | + | ||
| 297 | + template < | ||
| 298 | + int quant_mode, | ||
| 299 | + int staticML0LoopNum = Arch35MmadOpt::DYNAMIC_LOOP, | ||
| 300 | + int staticKL0LoopNum = Arch35MmadOpt::DYNAMIC_LOOP, | ||
| 301 | + class TensorB, | ||
| 302 | + class TensorC> | ||
| 303 | + __aicore__ inline | ||
| 304 | + void operator()(TensorB &gBTensor, TensorC &ubCTensor, | ||
| 305 | + AscendC::GlobalTensor<int32_t> gSparseBlockIdx, | ||
| 306 | + GemmCoord actualOriShape, | ||
| 307 | + uint32_t gatheredKvSTileIdx, uint32_t kvSeqlen, | ||
| 308 | + uint32_t kvSBaseTile, uint32_t blockShapeY, | ||
| 309 | + uint32_t yBlockNumAval, uint32_t yBlockNumRsvd, | ||
| 310 | + uint64_t prefixSumL0AStages, uint64_t prefixSumL0BStages, | ||
| 311 | + Arch::CrossCoreFlag mm1ToSmFlag, | ||
| 312 | + float scaleValue = 0.0f) | ||
| 313 | + { | ||
| 314 | + using CopyL0CToDst = typename TileCopy_::template CopyL0CToDst<TensorC>; | ||
| 315 | + CopyL0CToDst copyL0CToDstSub0; | ||
| 316 | + CopyL0CToDst copyL0CToDstSub1; | ||
| 317 | + /* | ||
| 318 | + if constexpr (HasParams<CopyL0CToDst>::value && quant_mode == 1) { | ||
| 319 | + using DstParams = typename CopyL0CToDst::Params; | ||
| 320 | + CopyL0CToDstSub0 = CopyL0CToDst(DstParams{scaleValue}); | ||
| 321 | + CopyL0CToDstSub1 = CopyL0CToDst(DstParams{scaleValue}); | ||
| 322 | + }*/ | ||
| 323 | + | ||
| 324 | + uint32_t rowNum = actualOriShape[0]; | ||
| 325 | + uint32_t embed = actualOriShape[2]; | ||
| 326 | + uint32_t curBaseTileSize = actualOriShape[1]; | ||
| 327 | + | ||
| 328 | + auto l1ALayoutTla = tla::MakeLayout<ElementA, LayoutTagL1A>(rowNum, embed); | ||
| 329 | + auto l1ATensorTla = tla::MakeTensor(l1ATensor[0], l1ALayoutTla, Arch::PositionL1{}); | ||
| 330 | + | ||
| 331 | + // P full base tile already on L1 | ||
| 332 | + uint32_t nL1LoopNum = Arch35MmadOpt::LoopNum(curBaseTileSize, l1BTileN); | ||
| 333 | + uint32_t mL0LoopNum = Arch35MmadOpt::LoopNum(rowNum, L0_TILE_M); | ||
| 334 | + uint32_t kL0LoopNum = Arch35MmadOpt::LoopNum(embed, L0_TILE_K); | ||
| 335 | + uint32_t mFixPAligned8 = Arch35MmadOpt::AlignUpPow2<8>(rowNum); | ||
| 336 | + uint32_t mPerSubCore = mFixPAligned8 / 2; | ||
| 337 | + bool l1ToL0ANoRepeatFlag = (mL0LoopNum == 1U) && (kL0LoopNum <= L0_STAGES); | ||
| 338 | + | ||
| 339 | + // while splitting the base tile S to 2 AIVs, | ||
| 340 | + // the order of the elements in each column is expected to be preserved, | ||
| 341 | + // which means a column in l0C cannot be chunked and processed by dualMode FixPipe seperately. | ||
| 342 | + // therefore, FixPipe won't launch until each portion(chunked only by columns, based on nbuffer strategy) | ||
| 343 | + // of the base tile is ready on l0C | ||
| 344 | + uint32_t nLoopCounterL1 = Arch35MmadOpt::GetCurLoopCounter(gatheredKvSTileIdx, nL1LoopNum); | ||
| 345 | + uint32_t nL1Offset = 0; | ||
| 346 | + for (uint32_t nL1Itr = 0; nL1Itr < nL1LoopNum; nL1Itr++) { | ||
| 347 | + uint32_t l1TileNAct = (nL1Itr == nL1LoopNum - 1) ? (curBaseTileSize - nL1Offset) : l1BTileN; | ||
| 348 | + uint32_t l1BBufId = nLoopCounterL1 % l1BBufNum; | ||
| 349 | + uint32_t l1BEventId = l1BBufId + 1; | ||
| 350 | + auto l1BLayoutTla = tla::MakeLayout<ElementB, LayoutTagL1B>(embed, l1TileNAct); | ||
| 351 | + auto l1BTensorTla = tla::MakeTensor(l1BTensor[l1BBufId], l1BLayoutTla, Arch::PositionL1{}); | ||
| 352 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BEventId); | ||
| 353 | + SparseKL1TileNLoad( | ||
| 354 | + gBTensor, l1BTensorTla, gSparseBlockIdx, gatheredKvSTileIdx, kvSeqlen, kvSBaseTile, blockShapeY, | ||
| 355 | + yBlockNumAval, yBlockNumRsvd, l1TileNAct, embed, nL1Offset); | ||
| 356 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1BEventId); | ||
| 357 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1BEventId); | ||
| 358 | + uint32_t nL0LoopNum = Arch35MmadOpt::LoopNum(l1TileNAct, L0_TILE_N); | ||
| 359 | + uint32_t lNLoopCounterL0 = Arch35MmadOpt::GetCurLoopCounter(nL1Itr, nL0LoopNum); | ||
| 360 | + uint32_t l0CLoopCounter = Arch35MmadOpt::GetCurLoopCounter(nLoopCounterL1, nL0LoopNum); | ||
| 361 | + uint32_t nL0Offset = 0; | ||
| 362 | + for (uint32_t nL0Itr = 0; nL0Itr < nL0LoopNum; nL0Itr++) { | ||
| 363 | + uint32_t l0TileNAct = (nL0Itr == nL0LoopNum - 1) ? (l1TileNAct - nL0Offset) : L0_TILE_N; | ||
| 364 | + // l0C nbuffer chunked only in n loop | ||
| 365 | + uint32_t l0CBufId = Arch35MmadOpt::StageId<L0_STAGES>(l0CLoopCounter); | ||
| 366 | + uint32_t l0CEventId = l0CBufId; | ||
| 367 | + auto l0CLayoutTla = tla::MakeLayoutL0C(rowNum, l0TileNAct); | ||
| 368 | + auto l0CTensorTla = tla::MakeTensor(l0CTensor[l0CBufId], l0CLayoutTla, Arch::PositionL0C{}); | ||
| 369 | + uint32_t mOffset = 0; | ||
| 370 | + uint32_t l0ALoopBase = static_cast<uint32_t>(prefixSumL0AStages); | ||
| 371 | + uint32_t l0BLoopBase = static_cast<uint32_t>(prefixSumL0BStages) + lNLoopCounterL0 * kL0LoopNum; | ||
| 372 | + for (uint32_t mL0Itr = 0; mL0Itr < Arch35MmadOpt::LoopBound<staticML0LoopNum>(mL0LoopNum); mL0Itr++) { | ||
| 373 | + uint32_t l0TileMAct = (mL0Itr == mL0LoopNum - 1) ? (rowNum - mOffset) : L0_TILE_M; | ||
| 374 | + // uint32_t mLoopCounter = GetCurLoopCounter(gatheredKvSTileIdx, mL0LoopNum, mL0Itr); | ||
| 375 | + // different m chunks will be concated in the same piece of l0C buffer | ||
| 376 | + auto l0CTensorTlaTile = GetTile(l0CTensorTla, | ||
| 377 | + tla::MakeCoord(mOffset, 0), tla::MakeShape(l0TileMAct, l0TileNAct)); | ||
| 378 | + uint32_t l0ALoopCounter = l0ALoopBase; | ||
| 379 | + uint32_t l0BLoopCounter = l0BLoopBase; | ||
| 380 | + uint32_t kOffset = 0; | ||
| 381 | + for (uint32_t kL0Itr = 0; kL0Itr < Arch35MmadOpt::LoopBound<staticKL0LoopNum>(kL0LoopNum); kL0Itr++) { | ||
| 382 | + uint32_t l0TileKAct = (kL0Itr == kL0LoopNum - 1) ? | ||
| 383 | + (embed - kOffset) : L0_TILE_K; | ||
| 384 | + uint32_t l0ABufId = Arch35MmadOpt::StageId<L0_STAGES>(l0ALoopCounter); | ||
| 385 | + uint32_t l0BBufId = Arch35MmadOpt::StageId<L0_STAGES>(l0BLoopCounter); | ||
| 386 | + uint32_t l0AEventId = l0ABufId; | ||
| 387 | + uint32_t l0BEventId = l0BBufId + 2; | ||
| 388 | + // when L0B buffers wouldn't be reused across the k loop | ||
| 389 | + // redundant L0B load caused by m loop can be avoided | ||
| 390 | + auto l1BTensorTlaTile = GetTile(l1BTensorTla, tla::MakeCoord(kOffset, nL0Offset), | ||
| 391 | + tla::MakeShape(l0TileKAct, l0TileNAct)); | ||
| 392 | + auto l0BLayoutTla = tla::MakeLayout<ElementB, LayoutTagL0B>(l0TileKAct, l0TileNAct); | ||
| 393 | + auto l0BTensorTla = tla::MakeTensor(l0BTensor[l0BBufId], l0BLayoutTla, Arch::PositionL0B{}); | ||
| 394 | + | ||
| 395 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0BEventId); | ||
| 396 | + copyL1ToL0B(l0BTensorTla, l1BTensorTlaTile); | ||
| 397 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(l0BEventId); | ||
| 398 | + if ((nL0Itr == nL0LoopNum - 1) && (mL0Itr == mL0LoopNum - 1) && (kL0Itr == kL0LoopNum - 1)) { | ||
| 399 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(l1BEventId); | ||
| 400 | + } | ||
| 401 | + | ||
| 402 | + auto l1ATensorTlaTile = GetTile(l1ATensorTla, tla::MakeCoord(mOffset, kOffset), | ||
| 403 | + tla::MakeShape(l0TileMAct, l0TileKAct)); | ||
| 404 | + auto l0ALayoutTla = tla::MakeLayout<ElementA, LayoutTagL0A>(l0TileMAct, l0TileKAct); | ||
| 405 | + auto l0ATensorTla = tla::MakeTensor(l0ATensor[l0ABufId], l0ALayoutTla, Arch::PositionL0A{}); | ||
| 406 | + | ||
| 407 | + if (l1ToL0ANoRepeatFlag && (nL1Itr == 0) && (nL0Itr == 0)) { | ||
| 408 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0AEventId); | ||
| 409 | + copyL1ToL0A(l0ATensorTla, l1ATensorTlaTile); | ||
| 410 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(l0AEventId); | ||
| 411 | + } | ||
| 412 | + | ||
| 413 | + bool initMmad = (kL0Itr == 0); | ||
| 414 | + uint32_t l0TileMAligned = Arch35MmadOpt::AlignUpPow2<16>(l0TileMAct); | ||
| 415 | + if (l1ToL0ANoRepeatFlag && (nL1Itr == 0) && (nL0Itr == 0)) { | ||
| 416 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(l0AEventId); | ||
| 417 | + } | ||
| 418 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(l0BEventId); | ||
| 419 | + if (mL0Itr == 0 && kL0Itr == 0) { | ||
| 420 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(l0CEventId); | ||
| 421 | + } | ||
| 422 | + tileMmad( | ||
| 423 | + l0CTensorTlaTile, | ||
| 424 | + l0ATensorTla, | ||
| 425 | + l0BTensorTla, | ||
| 426 | + l0TileMAligned, | ||
| 427 | + l0TileNAct, | ||
| 428 | + l0TileKAct, | ||
| 429 | + initMmad); | ||
| 430 | + if (l1ToL0ANoRepeatFlag && (nL1Itr == nL1LoopNum - 1) && (nL0Itr == nL0LoopNum - 1)) { | ||
| 431 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0AEventId); | ||
| 432 | + } | ||
| 433 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0BEventId); | ||
| 434 | + l0ALoopCounter++; | ||
| 435 | + l0BLoopCounter++; | ||
| 436 | + kOffset += L0_TILE_K; | ||
| 437 | + } | ||
| 438 | + mOffset += L0_TILE_M; | ||
| 439 | + l0ALoopBase += kL0LoopNum; | ||
| 440 | + } | ||
| 441 | + // fixpipe | ||
| 442 | + if (nL0Itr == 0) { | ||
| 443 | + // reverse crossCoreSync, do fixPipe only after ubCTensor is fully released | ||
| 444 | + WaitCrossCoreSync<4, PIPE_FIX>(mm1ToSmFlag); | ||
| 445 | + } | ||
| 446 | + AscendC::SetFlag<AscendC::HardEvent::M_FIX>(l0CEventId); | ||
| 447 | + AscendC::WaitFlag<AscendC::HardEvent::M_FIX>(l0CEventId); | ||
| 448 | + // 需要kernel传输ubCTensor的时候确保其shape的m,n是满足32B(8个32位元素)对齐的 | ||
| 449 | + // rounded up by 8 and splited in half to each AIV | ||
| 450 | + // valid rows in AIV0: [0, mFixPAligned8 / 2 - 1] | ||
| 451 | + // valid rows in AIV1: [mFixPAligned8 / 2, rowNum - 1] | ||
| 452 | + uint32_t nFixPAligned16 = Arch35MmadOpt::AlignUpPow2<16>(l0TileNAct); | ||
| 453 | + auto ubCTensorTlaTile = GetTile(ubCTensor, | ||
| 454 | + tla::MakeCoord(0, nL0Offset), tla::MakeShape(mPerSubCore, nFixPAligned16)); | ||
| 455 | + auto l0CTensorTlaTileSub0 = GetTile(l0CTensorTla, | ||
| 456 | + tla::MakeCoord(0, 0), tla::MakeShape(mPerSubCore, l0TileNAct)); | ||
| 457 | + auto l0CTensorTlaTileSub1 = GetTile(l0CTensorTla, | ||
| 458 | + tla::MakeCoord(mPerSubCore, 0), tla::MakeShape(mPerSubCore, l0TileNAct)); | ||
| 459 | + copyL0CToDstSub0(ubCTensorTlaTile, l0CTensorTlaTileSub0, false); | ||
| 460 | + copyL0CToDstSub1(ubCTensorTlaTile, l0CTensorTlaTileSub1, true); | ||
| 461 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(l0CEventId); | ||
| 462 | + lNLoopCounterL0++; | ||
| 463 | + l0CLoopCounter++; | ||
| 464 | + nL0Offset += L0_TILE_N; | ||
| 465 | + } | ||
| 466 | + nLoopCounterL1++; | ||
| 467 | + nL1Offset += l1BTileN; | ||
| 468 | + } | ||
| 469 | + // crossCoreSync after all fixPipe move | ||
| 470 | + SetCrossCoreSync<4, PIPE_FIX>(mm1ToSmFlag); | ||
| 471 | + } | ||
| 472 | + | ||
| 473 | +protected: | ||
| 474 | + /// Data members | ||
| 475 | + AscendC::LocalTensor<ElementA> l1ATensor[MAX_L1_STAGES]; | ||
| 476 | + AscendC::LocalTensor<ElementB> l1BTensor[MAX_L1_STAGES]; | ||
| 477 | + AscendC::LocalTensor<ElementA> l0ATensor[L0_STAGES]; | ||
| 478 | + AscendC::LocalTensor<ElementB> l0BTensor[L0_STAGES]; | ||
| 479 | + AscendC::LocalTensor<ElementAccumulator> l0CTensor[L0_STAGES]; | ||
| 480 | + | ||
| 481 | + TileMmad tileMmad; | ||
| 482 | + CopyL1ToL0A copyL1ToL0A; | ||
| 483 | + CopyL1ToL0B copyL1ToL0B; | ||
| 484 | + | ||
| 485 | + uint32_t l1ATileM; | ||
| 486 | + uint32_t l1BTileN; | ||
| 487 | + uint32_t l1ATileK; | ||
| 488 | + uint32_t l1BTileK; | ||
| 489 | + uint32_t l1ABufNum; | ||
| 490 | + uint32_t l1BBufNum; | ||
| 491 | + | ||
| 492 | + uint32_t l1PPingPongFlag = 0; | ||
| 493 | + uint32_t l0CPingPongFlag = 0; | ||
| 494 | + uint32_t l0ABPingPongFlag = 0; | ||
| 495 | +}; | ||
| 496 | +//////////////////////////////////////////////////////////////////// | ||
| 497 | + | ||
| 498 | +} // namespace NpuArch::Gemm::Block | ||
| 499 | + | ||
| @@ -0,0 +1,503 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @brief matmul implementation for single q&k^t base tile | ||
| 13 | + * This implementation is designed for the following senario: | ||
| 14 | + * A full q base tile is loaded to L1 from GM at the very beginning, | ||
| 15 | + * and it remains persistent until each k base tile is dealt | ||
| 16 | + * A full q*k^t base tile is loaded to UB from l0C, no workspace transit | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | +//////////////////////////////////////////////////////////////////// | ||
| 35 | + | ||
| 36 | +namespace NpuArch::Gemm::Block { | ||
| 37 | +//////////////////////////////////////////////////////////////////// | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + | ||
| 42 | +template <class T> | ||
| 43 | +struct HasParams { | ||
| 44 | + template <class U> | ||
| 45 | + static char test(typename U::Params*); | ||
| 46 | + template <class U> | ||
| 47 | + static int test(...); | ||
| 48 | + static constexpr bool value = sizeof(test<T>(0)) == sizeof(char); | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +struct Mm1L1TileHelper { | ||
| 52 | + uint32_t mm1L1TileM; | ||
| 53 | + uint32_t mm1L1TileN; | ||
| 54 | + uint32_t mm1L1TileKLeft; | ||
| 55 | + uint32_t mm1L1TileKRight; | ||
| 56 | + uint32_t qL1BufNum; | ||
| 57 | + uint32_t kL1BufNum; | ||
| 58 | + | ||
| 59 | + __aicore__ inline | ||
| 60 | + Mm1L1TileHelper() {} | ||
| 61 | + | ||
| 62 | + __aicore__ inline | ||
| 63 | + Mm1L1TileHelper( | ||
| 64 | + uint32_t m, | ||
| 65 | + uint32_t n, | ||
| 66 | + uint32_t kl, | ||
| 67 | + uint32_t kr, | ||
| 68 | + uint32_t pbn, | ||
| 69 | + uint32_t vbn) : | ||
| 70 | + mm1L1TileM(m), | ||
| 71 | + mm1L1TileN(n), | ||
| 72 | + mm1L1TileKLeft(kl), | ||
| 73 | + mm1L1TileKRight(kr), | ||
| 74 | + qL1BufNum(pbn), | ||
| 75 | + kL1BufNum(vbn) {} | ||
| 76 | +}; | ||
| 77 | + | ||
| 78 | + | ||
| 79 | +template < | ||
| 80 | + class L1TileShape_, | ||
| 81 | + class L0TileShape_, | ||
| 82 | + class ElementC_, | ||
| 83 | + class ElementBias_, | ||
| 84 | + class TileCopy_, | ||
| 85 | + class TileMmad_> | ||
| 86 | +struct BlockMmadTla< | ||
| 87 | + MmadAtlasA5BsaQK, | ||
| 88 | + L1TileShape_, | ||
| 89 | + L0TileShape_, | ||
| 90 | + int8_t, | ||
| 91 | + int8_t, | ||
| 92 | + ElementC_, | ||
| 93 | + ElementBias_, | ||
| 94 | + TileCopy_, | ||
| 95 | + TileMmad_> | ||
| 96 | +{ | ||
| 97 | +public: | ||
| 98 | + using DispatchPolicy = MmadAtlasA5BsaQK; | ||
| 99 | + using ArchTag = typename DispatchPolicy::ArchTag; | ||
| 100 | + using TileCopy = TileCopy_; | ||
| 101 | + using ElementA = int8_t; | ||
| 102 | + using ElementB = int8_t; | ||
| 103 | + using ElementC = ElementC_; | ||
| 104 | + | ||
| 105 | + using TileMmad = TileMmad_; | ||
| 106 | + | ||
| 107 | + using CopyL1ToL0A = typename TileCopy::CopyL1ToL0A; | ||
| 108 | + using CopyL1ToL0B = typename TileCopy::CopyL1ToL0B; | ||
| 109 | + | ||
| 110 | + using ElementAccumulator = typename TileCopy::ElementAccumulator; | ||
| 111 | + | ||
| 112 | + using LayoutTagL1A = typename TileCopy::LayoutTagL1A; | ||
| 113 | + using LayoutTagL1B = typename TileCopy::LayoutTagL1B; | ||
| 114 | + using LayoutTagL0A = typename TileCopy::LayoutTagL0A; | ||
| 115 | + using LayoutTagL0B = typename TileCopy::LayoutTagL0B; | ||
| 116 | + | ||
| 117 | + static constexpr uint32_t L0_STAGES = DispatchPolicy::L0_STAGES; | ||
| 118 | + static constexpr uint32_t L0_TILE_M = tla::get<0>(L0TileShape_{}); | ||
| 119 | + static constexpr uint32_t L0_TILE_N = tla::get<1>(L0TileShape_{}); | ||
| 120 | + static constexpr uint32_t L0_TILE_K = tla::get<2>(L0TileShape_{}); | ||
| 121 | + static constexpr uint32_t L0A_PINGPONG_BUF_SIZE = ArchTag::L0A_SIZE / L0_STAGES; | ||
| 122 | + static constexpr uint32_t L0B_PINGPONG_BUF_SIZE = ArchTag::L0B_SIZE / L0_STAGES; | ||
| 123 | + static constexpr uint32_t L0C_HALF_BUF_SIZE = ArchTag::L0C_SIZE / 2; | ||
| 124 | + static constexpr uint32_t L0C_PINGPONG_BUF_SIZE = L0C_HALF_BUF_SIZE / L0_STAGES; | ||
| 125 | + | ||
| 126 | + static constexpr uint32_t MAX_L1_STAGES = 3; // 编译期常量,为静态L1Tensor数组开辟准备。取一个buffer份数的极大值 | ||
| 127 | + static constexpr uint32_t V0_V1_FLAG_ID_OFFSET = 16; // 核间同步mode4,AIC侧需要两个flagId分别对应两个AIV | ||
| 128 | + | ||
| 129 | + __aicore__ inline | ||
| 130 | + BlockMmadTla(Arch::Resource<ArchTag> &resource, Mm1L1TileHelper &mm1L1TileHelper) | ||
| 131 | + { | ||
| 132 | + l1ATileM = mm1L1TileHelper.mm1L1TileN; | ||
| 133 | + l1BTileN = mm1L1TileHelper.mm1L1TileM; | ||
| 134 | + l1ATileK = mm1L1TileHelper.mm1L1TileKRight; | ||
| 135 | + l1BTileK = mm1L1TileHelper.mm1L1TileKLeft; | ||
| 136 | + l1ABufNum = mm1L1TileHelper.kL1BufNum; | ||
| 137 | + l1BBufNum = mm1L1TileHelper.qL1BufNum; | ||
| 138 | + | ||
| 139 | + for (uint32_t i = 0; i < l1ABufNum; i++) { | ||
| 140 | + l1ATensor[i] = resource.l1Buf.template GetBufferByByte<ElementA>( | ||
| 141 | + l1ATileM * l1ATileK * sizeof(ElementA) * i); | ||
| 142 | + } | ||
| 143 | + for (uint32_t i = 0; i < l1BBufNum; i++) { | ||
| 144 | + l1BTensor[i] = resource.l1Buf.template GetBufferByByte<ElementB>( | ||
| 145 | + l1ATileM * l1ATileK * sizeof(ElementA) * l1ABufNum + | ||
| 146 | + l1BTileK * l1BTileN * sizeof(ElementB) * i); | ||
| 147 | + } | ||
| 148 | + for (uint32_t i = 0; i < L0_STAGES; i++) { | ||
| 149 | + l0ATensor[i] = resource.l0ABuf.template GetBufferByByte<ElementA>( | ||
| 150 | + L0A_PINGPONG_BUF_SIZE * i); | ||
| 151 | + l0BTensor[i] = resource.l0BBuf.template GetBufferByByte<ElementB>( | ||
| 152 | + L0B_PINGPONG_BUF_SIZE * i); | ||
| 153 | + l0CTensor[i] = resource.l0CBuf.template GetBufferByByte<ElementAccumulator>( | ||
| 154 | + L0C_PINGPONG_BUF_SIZE * i); | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + /// Destructor | ||
| 159 | + __aicore__ inline | ||
| 160 | + ~BlockMmadTla() {} | ||
| 161 | + | ||
| 162 | + template <class TensorB> | ||
| 163 | + __aicore__ inline | ||
| 164 | + void loadQGM(TensorB &gBTensor, GemmCoord actualOriShape) | ||
| 165 | + { | ||
| 166 | + using CopyGmToL1B = typename TileCopy_::template CopyGmToL1B<TensorB>; | ||
| 167 | + CopyGmToL1B copyGmToL1B; | ||
| 168 | + uint32_t rowNum = actualOriShape[0]; | ||
| 169 | + uint32_t embed = actualOriShape[1]; | ||
| 170 | + //rowNum需要至少按照32对齐 | ||
| 171 | + auto l1BLayoutTla = tla::MakeLayout<ElementB, LayoutTagL1B>(embed, Arch35MmadOpt::AlignUpPow2<32>(rowNum)); | ||
| 172 | + auto l1BTensorTla = tla::MakeTensor(l1BTensor[0], l1BLayoutTla, Arch::PositionL1{}); | ||
| 173 | + auto l1BTensorTlaTile = GetTile(l1BTensorTla, | ||
| 174 | + tla::MakeCoord(0, 0), tla::MakeShape(embed, rowNum)); | ||
| 175 | + auto gBTensorTlaTile = GetTile(gBTensor, | ||
| 176 | + tla::MakeCoord(0, 0), tla::MakeShape(embed, rowNum)); | ||
| 177 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 178 | + copyGmToL1B(l1BTensorTlaTile, gBTensorTlaTile); | ||
| 179 | + | ||
| 180 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(EVENT_ID0); | ||
| 181 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(EVENT_ID0); | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 185 | + __aicore__ inline | ||
| 186 | + void SetCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 187 | + { | ||
| 188 | + // in mode 4, AIC set for 2 AIVs seperately | ||
| 189 | + if constexpr (MODE == 4U) { | ||
| 190 | + uint16_t flagIdV0 = crossCoreFlag.id; | ||
| 191 | + uint16_t flagIdV1 = flagIdV0 + V0_V1_FLAG_ID_OFFSET; | ||
| 192 | + Arch::CrossCoreFlag crossCoreFlagV1(flagIdV1); | ||
| 193 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlag); | ||
| 194 | + Arch::CrossCoreSetFlag<MODE, PIPE>(crossCoreFlagV1); | ||
| 195 | + } | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + template <uint32_t MODE, pipe_t PIPE> | ||
| 199 | + __aicore__ inline | ||
| 200 | + void WaitCrossCoreSync(Arch::CrossCoreFlag &crossCoreFlag) | ||
| 201 | + { | ||
| 202 | + // in mode 4, AIC wait for 2 AIVs seperately | ||
| 203 | + if constexpr (MODE == 4U) { | ||
| 204 | + uint16_t flagIdV0 = crossCoreFlag.id; | ||
| 205 | + uint16_t flagIdV1 = flagIdV0 + V0_V1_FLAG_ID_OFFSET; | ||
| 206 | + Arch::CrossCoreFlag crossCoreFlagV1(flagIdV1); | ||
| 207 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlag); | ||
| 208 | + Arch::CrossCoreWaitFlag<MODE, PIPE>(crossCoreFlagV1); | ||
| 209 | + } | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + __aicore__ inline | ||
| 213 | + uint32_t GetCurLoopCounter(uint32_t outterLoopItr, uint32_t curLoopNum, uint32_t curLoopItr) | ||
| 214 | + { | ||
| 215 | + return outterLoopItr * curLoopNum + curLoopItr; | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + template <class TensorA, class TensorL1A> | ||
| 219 | + __aicore__ inline | ||
| 220 | + void SparseKL1TileNLoad(TensorA &gATensor, TensorL1A &l1ATensorTla, | ||
| 221 | + AscendC::GlobalTensor<int32_t> gSparseBlockIdx, | ||
| 222 | + uint32_t gatheredKvSTileIdx, uint32_t kvSeqlen, | ||
| 223 | + uint32_t kvSBaseTile, uint32_t blockShapeY, | ||
| 224 | + uint32_t yBlockNumAval, uint32_t yBlockNumRsvd, | ||
| 225 | + uint32_t l1BTileNAct, uint32_t embed, | ||
| 226 | + uint32_t kvSBaseTileInnerOffset) | ||
| 227 | + { | ||
| 228 | + using CopyGmToL1A = typename TileCopy_::template CopyGmToL1A<TensorA>; | ||
| 229 | + CopyGmToL1A copyGmToL1A; | ||
| 230 | + uint32_t baseTileStartOffset = gatheredKvSTileIdx * kvSBaseTile + kvSBaseTileInnerOffset; | ||
| 231 | + uint32_t baseTileEndOffset = baseTileStartOffset + l1BTileNAct; | ||
| 232 | + // 稀疏情况下对实际选中的部分gather后进行基本块切分 | ||
| 233 | + // 当前处理的Yblock在gather的序列中的起始偏移,初始值为当前基块的起始偏移 | ||
| 234 | + uint32_t gatheredStartOffset = baseTileStartOffset; | ||
| 235 | + // 当前处理的Yblock gather后的下标,初始值为基本块起始偏移对应的按Y方向稀疏block的gather后起始下标 | ||
| 236 | + uint32_t gatheredYBlockIdx = gatheredStartOffset / blockShapeY; | ||
| 237 | + // 当前基本块起始偏移对应的按Y方向稀疏后的block内起始偏移 | ||
| 238 | + uint32_t yBlockInnerStartOffset = gatheredStartOffset % blockShapeY; | ||
| 239 | + // 当前处理的Yblock原始的下标,初始值为基本块对应的按Y方向稀疏block的原始起始下标 | ||
| 240 | + uint32_t oriYBlockIdx = gSparseBlockIdx.GetValue(gatheredYBlockIdx); | ||
| 241 | + // 当前处理的Yblock起始位置在原始序列中的偏移,初始值为基本块在原始序列中的起始偏移 | ||
| 242 | + uint32_t oriStartOffset = oriYBlockIdx * blockShapeY + yBlockInnerStartOffset; | ||
| 243 | + // 逐稀疏block搬移填充基本块过程中,已处理的累积序列长度 | ||
| 244 | + uint32_t dealtLenAccum = 0; | ||
| 245 | + | ||
| 246 | + while (dealtLenAccum < l1BTileNAct && gatheredYBlockIdx < yBlockNumRsvd && | ||
| 247 | + oriYBlockIdx < yBlockNumAval && oriStartOffset < kvSeqlen) { | ||
| 248 | + uint32_t curYBlockSize = blockShapeY; | ||
| 249 | + if (oriYBlockIdx == yBlockNumAval - 1) { | ||
| 250 | + curYBlockSize = kvSeqlen - oriYBlockIdx * blockShapeY; | ||
| 251 | + } | ||
| 252 | + uint32_t gatheredEndOffset = | ||
| 253 | + min(gatheredYBlockIdx * blockShapeY + curYBlockSize, | ||
| 254 | + baseTileEndOffset); | ||
| 255 | + // 当前循环处理的序列长度 | ||
| 256 | + uint32_t curDealtLen = gatheredEndOffset - gatheredStartOffset; | ||
| 257 | + if (curDealtLen == 0) { | ||
| 258 | + break; | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | + auto l1ATensorTlaTile = GetTile(l1ATensorTla, | ||
| 262 | + tla::MakeCoord(dealtLenAccum, 0), tla::MakeShape(curDealtLen, embed)); | ||
| 263 | + auto gATensorTlaTile = GetTile(gATensor, | ||
| 264 | + tla::MakeCoord(oriStartOffset, 0), tla::MakeShape(curDealtLen, embed)); | ||
| 265 | + copyGmToL1A(l1ATensorTlaTile, gATensorTlaTile); | ||
| 266 | + // 为下一次循环刷新循环变量 | ||
| 267 | + dealtLenAccum += curDealtLen; | ||
| 268 | + gatheredStartOffset += curDealtLen; | ||
| 269 | + gatheredYBlockIdx = gatheredStartOffset / blockShapeY; | ||
| 270 | + yBlockInnerStartOffset = gatheredStartOffset % blockShapeY; | ||
| 271 | + if (dealtLenAccum < l1BTileNAct) { | ||
| 272 | + oriYBlockIdx = gSparseBlockIdx.GetValue(gatheredYBlockIdx); | ||
| 273 | + oriStartOffset = oriYBlockIdx * blockShapeY + yBlockInnerStartOffset; | ||
| 274 | + } | ||
| 275 | + } | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + | ||
| 279 | + template < | ||
| 280 | + int quant_mode, | ||
| 281 | + int staticML0LoopNum = Arch35MmadOpt::DYNAMIC_LOOP, | ||
| 282 | + int staticKL0LoopNum = Arch35MmadOpt::DYNAMIC_LOOP, | ||
| 283 | + class TensorA, | ||
| 284 | + class TensorC> | ||
| 285 | + __aicore__ inline | ||
| 286 | + void operator()(TensorA &gATensor, TensorC &ubCTensor, | ||
| 287 | + AscendC::GlobalTensor<int32_t> gSparseBlockIdx, | ||
| 288 | + GemmCoord actualOriShape, | ||
| 289 | + uint32_t gatheredKvSTileIdx, uint32_t kvSeqlen, | ||
| 290 | + uint32_t kvSBaseTile, uint32_t blockShapeY, | ||
| 291 | + uint32_t yBlockNumAval, uint32_t yBlockNumRsvd, | ||
| 292 | + uint64_t prefixSumL0AStages, uint64_t prefixSumL0BStages, | ||
| 293 | + Arch::CrossCoreFlag mm1ToSmFlag, | ||
| 294 | + float scaleValue = 0.0f) | ||
| 295 | + { | ||
| 296 | + using CopyL0CToDst = typename TileCopy_::template CopyL0CToDst<TensorC>; | ||
| 297 | + CopyL0CToDst copyL0CToDstSub0; | ||
| 298 | + CopyL0CToDst copyL0CToDstSub1; | ||
| 299 | + | ||
| 300 | + uint32_t rowNum = Arch35MmadOpt::AlignUpPow2<32>(actualOriShape[0]); | ||
| 301 | + uint32_t embed = actualOriShape[2]; | ||
| 302 | + uint32_t curBaseTileSize = actualOriShape[1]; | ||
| 303 | + | ||
| 304 | + auto l1BLayoutTla = tla::MakeLayout<ElementB, LayoutTagL1B>(embed, rowNum); | ||
| 305 | + auto l1BTensorTla = tla::MakeTensor(l1BTensor[0], l1BLayoutTla, Arch::PositionL1{}); | ||
| 306 | + | ||
| 307 | + // P full base tile already on L1 | ||
| 308 | + uint32_t nL1LoopNum = Arch35MmadOpt::LoopNum(curBaseTileSize, l1ATileM); | ||
| 309 | + uint32_t mL0LoopNum = Arch35MmadOpt::LoopNum(rowNum, L0_TILE_M); | ||
| 310 | + uint32_t kL0LoopNum = Arch35MmadOpt::LoopNum(embed, L0_TILE_K); | ||
| 311 | + uint32_t mFixPAligned64 = Arch35MmadOpt::AlignUpPow2<64>(rowNum); | ||
| 312 | + uint32_t mFixPAligned32 = Arch35MmadOpt::AlignUpPow2<32>(rowNum); | ||
| 313 | + | ||
| 314 | + uint32_t mPerSubCore = mFixPAligned64 / 2; | ||
| 315 | + | ||
| 316 | + bool l1ToL0ANoRepeatFlag = (mL0LoopNum == 1U) && (kL0LoopNum <= L0_STAGES); | ||
| 317 | + | ||
| 318 | + uint32_t nLoopCounterL1 = Arch35MmadOpt::GetCurLoopCounter(gatheredKvSTileIdx, nL1LoopNum); | ||
| 319 | + uint32_t nL1Offset = 0; | ||
| 320 | + //原本是mxkxn的矩阵变成了nxkxm; | ||
| 321 | + for (uint32_t nL1Itr = 0; nL1Itr < nL1LoopNum; nL1Itr++) { | ||
| 322 | + uint32_t l1TileNAct = (nL1Itr == nL1LoopNum - 1) ? (curBaseTileSize - nL1Offset) : l1ATileM; | ||
| 323 | + uint32_t l1ABufId = nLoopCounterL1 % l1ABufNum; | ||
| 324 | + uint32_t l1AEventId = l1ABufId + 1; | ||
| 325 | + auto l1ALayoutTla = tla::MakeLayout<ElementA, LayoutTagL1A>(l1TileNAct, embed); | ||
| 326 | + auto l1ATensorTla = tla::MakeTensor(l1ATensor[l1ABufId], l1ALayoutTla, Arch::PositionL1{}); | ||
| 327 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1AEventId); | ||
| 328 | + SparseKL1TileNLoad( | ||
| 329 | + gATensor, l1ATensorTla, gSparseBlockIdx, gatheredKvSTileIdx, kvSeqlen, kvSBaseTile, blockShapeY, | ||
| 330 | + yBlockNumAval, yBlockNumRsvd, l1TileNAct, embed, nL1Offset); | ||
| 331 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1AEventId); | ||
| 332 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1AEventId); | ||
| 333 | + uint32_t nL0LoopNum = Arch35MmadOpt::LoopNum(l1TileNAct, L0_TILE_N); | ||
| 334 | + uint32_t lNLoopCounterL0 = Arch35MmadOpt::GetCurLoopCounter(nL1Itr, nL0LoopNum); | ||
| 335 | + uint32_t l0CLoopCounter = Arch35MmadOpt::GetCurLoopCounter(nLoopCounterL1, nL0LoopNum); | ||
| 336 | + uint32_t nL0Offset = 0; | ||
| 337 | + for (uint32_t nL0Itr = 0; nL0Itr < nL0LoopNum; nL0Itr++) { | ||
| 338 | + uint32_t l0TileNAct = (nL0Itr == nL0LoopNum - 1) ? (l1TileNAct - nL0Offset) : L0_TILE_N; | ||
| 339 | + // l0C nbuffer chunked only in n loop | ||
| 340 | + uint32_t l0CBufId = Arch35MmadOpt::StageId<1>(l0CLoopCounter); | ||
| 341 | + uint32_t l0CEventId = l0CBufId; | ||
| 342 | + auto l0CLayoutTla = tla::MakeLayoutL0C(l0TileNAct, mFixPAligned64); | ||
| 343 | + auto l0CTensorTla = tla::MakeTensor(l0CTensor[l0CBufId], l0CLayoutTla, Arch::PositionL0C{}); | ||
| 344 | + uint32_t mOffset = 0; | ||
| 345 | + uint32_t l0ALoopBase = static_cast<uint32_t>(prefixSumL0AStages) + lNLoopCounterL0 * kL0LoopNum; | ||
| 346 | + uint32_t l0BLoopBase = static_cast<uint32_t>(prefixSumL0BStages); | ||
| 347 | + for (uint32_t mL0Itr = 0; mL0Itr < Arch35MmadOpt::LoopBound<staticML0LoopNum>(mL0LoopNum); mL0Itr++) { | ||
| 348 | + uint32_t l0TileMAct = (mL0Itr == mL0LoopNum - 1) ? (rowNum - mOffset) : L0_TILE_M; | ||
| 349 | + // uint32_t mLoopCounter = GetCurLoopCounter(gatheredKvSTileIdx, mL0LoopNum, mL0Itr); | ||
| 350 | + // different m chunks will be concated in the same piece of l0C buffer | ||
| 351 | + auto l0CTensorTlaTile = GetTile(l0CTensorTla, | ||
| 352 | + tla::MakeCoord(0, mOffset), tla::MakeShape(l0TileNAct, l0TileMAct)); | ||
| 353 | + uint32_t l0ALoopCounter = l0ALoopBase; | ||
| 354 | + uint32_t l0BLoopCounter = l0BLoopBase; | ||
| 355 | + uint32_t kOffset = 0; | ||
| 356 | + | ||
| 357 | + for (uint32_t kL0Itr = 0; kL0Itr < Arch35MmadOpt::LoopBound<staticKL0LoopNum>(kL0LoopNum); kL0Itr++) { | ||
| 358 | + uint32_t l0TileKAct = (kL0Itr == kL0LoopNum - 1) ? | ||
| 359 | + (embed - kOffset) : L0_TILE_K; | ||
| 360 | + uint32_t l0ABufId = Arch35MmadOpt::StageId<L0_STAGES>(l0ALoopCounter); | ||
| 361 | + uint32_t l0BBufId = Arch35MmadOpt::StageId<L0_STAGES>(l0BLoopCounter); | ||
| 362 | + uint32_t l0AEventId = l0ABufId; | ||
| 363 | + uint32_t l0BEventId = l0BBufId + 2; | ||
| 364 | + // when L0B buffers wouldn't be reused across the k loop | ||
| 365 | + // redundant L0B load caused by m loop can be avoided | ||
| 366 | + auto l1ATensorTlaTile = GetTile(l1ATensorTla, tla::MakeCoord(nL0Offset, kOffset), | ||
| 367 | + tla::MakeShape(l0TileNAct, l0TileKAct)); | ||
| 368 | + auto l0ALayoutTla = tla::MakeLayout<ElementA, LayoutTagL0A>(l0TileNAct, l0TileKAct); | ||
| 369 | + auto l0ATensorTla = tla::MakeTensor(l0ATensor[l0ABufId], l0ALayoutTla, Arch::PositionL0A{}); | ||
| 370 | + | ||
| 371 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0AEventId); | ||
| 372 | + copyL1ToL0A(l0ATensorTla, l1ATensorTlaTile); | ||
| 373 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(l0AEventId); | ||
| 374 | + if ((nL0Itr == nL0LoopNum - 1) && (mL0Itr == mL0LoopNum - 1) && (kL0Itr == kL0LoopNum - 1)) { | ||
| 375 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(l1AEventId); | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + auto l1BTensorTlaTile = GetTile(l1BTensorTla, tla::MakeCoord(kOffset, mOffset), | ||
| 379 | + tla::MakeShape(l0TileKAct, l0TileMAct)); | ||
| 380 | + auto l0BLayoutTla = tla::MakeLayout<ElementB, LayoutTagL0B>(l0TileKAct, l0TileMAct); | ||
| 381 | + auto l0BTensorTla = tla::MakeTensor(l0BTensor[l0BBufId], l0BLayoutTla, Arch::PositionL0B{}); | ||
| 382 | + | ||
| 383 | + if (l1ToL0ANoRepeatFlag && (nL1Itr == 0) && (nL0Itr == 0)) { | ||
| 384 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0BEventId); | ||
| 385 | + copyL1ToL0B(l0BTensorTla, l1BTensorTlaTile); | ||
| 386 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(l0BEventId); | ||
| 387 | + } | ||
| 388 | + | ||
| 389 | + bool initMmad = (kL0Itr == 0); | ||
| 390 | + //uint32_t l0TileMAligned = Arch35MmadOpt::AlignUpPow2<16>(l0TileMAct); | ||
| 391 | + uint32_t l0TileNAligned = Arch35MmadOpt::AlignUpPow2<16>(l0TileNAct); | ||
| 392 | + if (l1ToL0ANoRepeatFlag && (nL1Itr == 0) && (nL0Itr == 0)) { | ||
| 393 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(l0BEventId); | ||
| 394 | + } | ||
| 395 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(l0AEventId); | ||
| 396 | + if (mL0Itr == 0 && kL0Itr == 0) { | ||
| 397 | + // AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(l0CEventId); | ||
| 398 | + } | ||
| 399 | + tileMmad( | ||
| 400 | + l0CTensorTlaTile, | ||
| 401 | + l0ATensorTla, | ||
| 402 | + l0BTensorTla, | ||
| 403 | + l0TileNAligned, | ||
| 404 | + l0TileMAct, | ||
| 405 | + l0TileKAct, | ||
| 406 | + initMmad, | ||
| 407 | + mL0Itr == mL0LoopNum - 1? 3 : 2); | ||
| 408 | + if (l1ToL0ANoRepeatFlag && (nL1Itr == nL1LoopNum - 1) && (nL0Itr == nL0LoopNum - 1)) { | ||
| 409 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0BEventId); | ||
| 410 | + } | ||
| 411 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0AEventId); | ||
| 412 | + l0ALoopCounter++; | ||
| 413 | + l0BLoopCounter++; | ||
| 414 | + kOffset += L0_TILE_K; | ||
| 415 | + } | ||
| 416 | + mOffset += L0_TILE_M; | ||
| 417 | + l0ALoopBase += kL0LoopNum; | ||
| 418 | + } | ||
| 419 | + // fixpipe | ||
| 420 | + if (nL0Itr == 0) { | ||
| 421 | + // reverse crossCoreSync, do fixPipe only after ubCTensor is fully released | ||
| 422 | + WaitCrossCoreSync<4, PIPE_FIX>(mm1ToSmFlag); | ||
| 423 | + } | ||
| 424 | + //AscendC::SetFlag<AscendC::HardEvent::M_FIX>(l0CEventId); | ||
| 425 | + // AscendC::WaitFlag<AscendC::HardEvent::M_FIX>(l0CEventId); | ||
| 426 | + | ||
| 427 | + uint32_t nFixPAligned16 = Arch35MmadOpt::AlignUpPow2<16>(l0TileNAct); | ||
| 428 | + | ||
| 429 | + float scale = scaleValue; | ||
| 430 | + int32_t curBaseTileSizeAligned16 = Arch35MmadOpt::AlignUpPow2<16>(curBaseTileSize); | ||
| 431 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams0, intriParams1; | ||
| 432 | + intriParams0.nSize = 32; | ||
| 433 | + intriParams0.mSize = nFixPAligned16; | ||
| 434 | + intriParams0.srcStride = nFixPAligned16; | ||
| 435 | + intriParams0.dstStride = 32; | ||
| 436 | + intriParams0.params.srcNdStride = 2 * nFixPAligned16; | ||
| 437 | + intriParams0.params.dstNdStride = curBaseTileSizeAligned16 * 32; | ||
| 438 | + intriParams0.params.ndNum = mPerSubCore == 32 ? 1:2; | ||
| 439 | + intriParams0.deqScalar = static_cast<uint64_t>(*reinterpret_cast<int32_t*>(&scale)); | ||
| 440 | + intriParams0.quantPre = QuantMode_t::DEQF16; | ||
| 441 | + intriParams0.reluEn = false; | ||
| 442 | + intriParams0.unitFlag = 3; | ||
| 443 | + intriParams0.dualDstCtl = 0; | ||
| 444 | + intriParams0.subBlockId = false; | ||
| 445 | + | ||
| 446 | + intriParams1.nSize = 32; | ||
| 447 | + intriParams1.mSize = nFixPAligned16; | ||
| 448 | + intriParams1.srcStride = nFixPAligned16; | ||
| 449 | + intriParams1.dstStride = 32; | ||
| 450 | + intriParams1.params.srcNdStride = 2*nFixPAligned16; | ||
| 451 | + intriParams1.params.dstNdStride = curBaseTileSizeAligned16 * 32; | ||
| 452 | + intriParams1.params.ndNum = (mFixPAligned32 == 64 || mFixPAligned32 == 96) ? 1 : 2; | ||
| 453 | + intriParams1.deqScalar = static_cast<uint64_t>(*reinterpret_cast<int32_t*>(&scale)); | ||
| 454 | + intriParams1.quantPre = QuantMode_t::DEQF16; | ||
| 455 | + intriParams1.reluEn = false; | ||
| 456 | + intriParams1.unitFlag = 3; | ||
| 457 | + intriParams1.dualDstCtl = 0; | ||
| 458 | + intriParams1.subBlockId = true; | ||
| 459 | + constexpr static AscendC::FixpipeConfig CFG_ROW_MAJOR_UB = {AscendC::CO2Layout::ROW_MAJOR, true}; | ||
| 460 | + AscendC::Fixpipe<half, int32_t, CFG_ROW_MAJOR_UB>(ubCTensor.data()[nL0Itr * L0_TILE_N * 32], l0CTensor[l0CBufId], intriParams0); | ||
| 461 | + if (rowNum > 32) { | ||
| 462 | + AscendC::Fixpipe<half, int32_t, CFG_ROW_MAJOR_UB>(ubCTensor.data()[nL0Itr * L0_TILE_N * 32], l0CTensor[l0CBufId][mPerSubCore * nFixPAligned16], intriParams1); | ||
| 463 | + } | ||
| 464 | + | ||
| 465 | + // AscendC::SetFlag<AscendC::HardEvent::FIX_M>(l0CEventId); | ||
| 466 | + lNLoopCounterL0++; | ||
| 467 | + l0CLoopCounter++; | ||
| 468 | + nL0Offset += L0_TILE_N; | ||
| 469 | + } | ||
| 470 | + nLoopCounterL1++; | ||
| 471 | + nL1Offset += l1ATileM; | ||
| 472 | + } | ||
| 473 | + // crossCoreSync after all fixPipe move | ||
| 474 | + SetCrossCoreSync<4, PIPE_FIX>(mm1ToSmFlag); | ||
| 475 | + } | ||
| 476 | + | ||
| 477 | +protected: | ||
| 478 | + /// Data members | ||
| 479 | + AscendC::LocalTensor<ElementA> l1ATensor[MAX_L1_STAGES]; | ||
| 480 | + AscendC::LocalTensor<ElementB> l1BTensor[MAX_L1_STAGES]; | ||
| 481 | + AscendC::LocalTensor<ElementA> l0ATensor[L0_STAGES]; | ||
| 482 | + AscendC::LocalTensor<ElementB> l0BTensor[L0_STAGES]; | ||
| 483 | + AscendC::LocalTensor<ElementAccumulator> l0CTensor[L0_STAGES]; | ||
| 484 | + | ||
| 485 | + TileMmad tileMmad; | ||
| 486 | + CopyL1ToL0A copyL1ToL0A; | ||
| 487 | + CopyL1ToL0B copyL1ToL0B; | ||
| 488 | + | ||
| 489 | + uint32_t l1ATileM; | ||
| 490 | + uint32_t l1BTileN; | ||
| 491 | + uint32_t l1ATileK; | ||
| 492 | + uint32_t l1BTileK; | ||
| 493 | + uint32_t l1ABufNum; | ||
| 494 | + uint32_t l1BBufNum; | ||
| 495 | + | ||
| 496 | + uint32_t l1PPingPongFlag = 0; | ||
| 497 | + uint32_t l0CPingPongFlag = 0; | ||
| 498 | + uint32_t l0ABPingPongFlag = 0; | ||
| 499 | +}; | ||
| 500 | +//////////////////////////////////////////////////////////////////// | ||
| 501 | + | ||
| 502 | +} // namespace NpuArch::Gemm::Block | ||
| 503 | + | ||
| @@ -0,0 +1,61 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace NpuArch::Gemm | ||
| 18 | +{ | ||
| 19 | + | ||
| 20 | +// Block Mmad Policies | ||
| 21 | + | ||
| 22 | +template <bool ASYNC_ = false> | ||
| 23 | +struct MmadAtlasA2Base { | ||
| 24 | + using ArchTag = Arch::AtlasA2; | ||
| 25 | + static constexpr uint32_t ASYNC = ASYNC_; | ||
| 26 | +}; | ||
| 27 | + | ||
| 28 | +template <bool ASYNC_ = false> | ||
| 29 | +struct MmadAtlasA5Base { | ||
| 30 | + using ArchTag = Arch::AtlasA5; | ||
| 31 | + static constexpr uint32_t ASYNC = ASYNC_; | ||
| 32 | +}; | ||
| 33 | + | ||
| 34 | +using MmadAtlasA2 = MmadAtlasA2Base<false>; | ||
| 35 | +using MmadAtlasA5 = MmadAtlasA5Base<false>; | ||
| 36 | + | ||
| 37 | +template <bool PAGED_CACHE_FLAG_ = false, bool ENABLE_UNIT_FLAG_ = false> | ||
| 38 | +struct MmadAtlasA2SFAIQK : public MmadAtlasA2 { | ||
| 39 | + static constexpr uint32_t STAGES = 2; | ||
| 40 | + static constexpr bool PAGED_CACHE_FLAG = PAGED_CACHE_FLAG_; | ||
| 41 | + static constexpr bool ENABLE_UNIT_FLAG = ENABLE_UNIT_FLAG_; | ||
| 42 | +}; | ||
| 43 | + | ||
| 44 | +template <bool PAGED_CACHE_FLAG_ = false, bool ENABLE_UNIT_FLAG_ = false> | ||
| 45 | +struct MmadAtlasA2SFAIPV : public MmadAtlasA2 { | ||
| 46 | + static constexpr uint32_t STAGES = 2; | ||
| 47 | + static constexpr bool PAGED_CACHE_FLAG = PAGED_CACHE_FLAG_; | ||
| 48 | + static constexpr bool ENABLE_UNIT_FLAG = ENABLE_UNIT_FLAG_; | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +struct MmadAtlasA5BsaQK : public MmadAtlasA5 { | ||
| 52 | + static constexpr uint32_t L0_STAGES = 2; | ||
| 53 | +}; | ||
| 54 | + | ||
| 55 | +struct MmadAtlasA5BsaPV : public MmadAtlasA5 { | ||
| 56 | + static constexpr uint32_t L0_STAGES = 2; | ||
| 57 | +}; | ||
| 58 | + | ||
| 59 | +} // namespace NpuArch::Gemm | ||
| 60 | + | ||
| 61 | + | ||
| @@ -0,0 +1,28 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace NpuArch::Gemm | ||
| 17 | +{ | ||
| 18 | +template <class Element_, class Layout_, AscendC::TPosition POSITION_ = AscendC::TPosition::GM> | ||
| 19 | +struct GemmType | ||
| 20 | +{ | ||
| 21 | + using Element = Element_; | ||
| 22 | + using Layout = Layout_; | ||
| 23 | + static constexpr AscendC::TPosition POSITION = POSITION_; | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +} // namespace NpuArch::Gemm | ||
| 27 | + | ||
| 28 | + | ||
| @@ -0,0 +1,347 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace NpuArch::Gemm::helper | ||
| 21 | +{ | ||
| 22 | + | ||
| 23 | +template<class Element, class Layout> | ||
| 24 | +struct L1AlignHelper { | ||
| 25 | + static_assert(DEPENDENT_FALSE<Element>, "Unsupported align helper, can not find the specialization."); | ||
| 26 | +}; | ||
| 27 | + | ||
| 28 | +template<class Element> | ||
| 29 | +struct L1AlignHelper<Element, layout::RowMajor> { | ||
| 30 | + static constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 31 | + static constexpr uint32_t M_ALIGNED = C0_NUM_PER_FRACTAL; | ||
| 32 | + static constexpr uint32_t K_ALIGNED = ELE_NUM_PER_C0; | ||
| 33 | + static constexpr uint32_t N_ALIGNED = ELE_NUM_PER_C0; | ||
| 34 | +}; | ||
| 35 | + | ||
| 36 | +template<class Element> | ||
| 37 | +struct L1AlignHelper<Element, layout::ColumnMajor> { | ||
| 38 | + static constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 39 | + static constexpr uint32_t M_ALIGNED = ELE_NUM_PER_C0; | ||
| 40 | + static constexpr uint32_t K_ALIGNED = ELE_NUM_PER_C0; | ||
| 41 | + static constexpr uint32_t N_ALIGNED = C0_NUM_PER_FRACTAL; | ||
| 42 | +}; | ||
| 43 | + | ||
| 44 | +template<class Element> | ||
| 45 | +struct L1AlignHelper<Element, layout::PaddingRowMajor> { | ||
| 46 | + static constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 47 | + static constexpr uint32_t M_ALIGNED = C0_NUM_PER_FRACTAL; | ||
| 48 | + static constexpr uint32_t K_ALIGNED = ELE_NUM_PER_C0; | ||
| 49 | + static constexpr uint32_t N_ALIGNED = ELE_NUM_PER_C0; | ||
| 50 | +}; | ||
| 51 | + | ||
| 52 | +template<class Element> | ||
| 53 | +struct L1AlignHelper<Element, layout::PaddingColumnMajor> { | ||
| 54 | + static constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 55 | + static constexpr uint32_t M_ALIGNED = ELE_NUM_PER_C0; | ||
| 56 | + static constexpr uint32_t K_ALIGNED = ELE_NUM_PER_C0; | ||
| 57 | + static constexpr uint32_t N_ALIGNED = C0_NUM_PER_FRACTAL; | ||
| 58 | +}; | ||
| 59 | + | ||
| 60 | +template<class Element> | ||
| 61 | +struct L1AlignHelper<Element, layout::zN> { | ||
| 62 | + static constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 63 | + static constexpr uint32_t M_ALIGNED = C0_NUM_PER_FRACTAL; | ||
| 64 | + static constexpr uint32_t K_ALIGNED = ELE_NUM_PER_C0; | ||
| 65 | + static constexpr uint32_t N_ALIGNED = ELE_NUM_PER_C0; | ||
| 66 | +}; | ||
| 67 | + | ||
| 68 | +template<class Element> | ||
| 69 | +struct L1AlignHelper<Element, layout::nZ> { | ||
| 70 | + static constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 71 | + static constexpr uint32_t M_ALIGNED = ELE_NUM_PER_C0; | ||
| 72 | + static constexpr uint32_t K_ALIGNED = ELE_NUM_PER_C0; | ||
| 73 | + static constexpr uint32_t N_ALIGNED = C0_NUM_PER_FRACTAL; | ||
| 74 | +}; | ||
| 75 | + | ||
| 76 | +template<class ElementA, class ElementB> | ||
| 77 | +struct ElementAccumulatorSelector { | ||
| 78 | + static_assert(DEPENDENT_FALSE<ElementA>, | ||
| 79 | + "Unsupported element accumulator selector, can not find the specialization."); | ||
| 80 | +}; | ||
| 81 | + | ||
| 82 | +template<> | ||
| 83 | +struct ElementAccumulatorSelector<half, half> { | ||
| 84 | + using ElementAccumulator = float; | ||
| 85 | +}; | ||
| 86 | + | ||
| 87 | +template<> | ||
| 88 | +struct ElementAccumulatorSelector<float, float> { | ||
| 89 | + using ElementAccumulator = float; | ||
| 90 | +}; | ||
| 91 | + | ||
| 92 | +template<> | ||
| 93 | +struct ElementAccumulatorSelector<int8_t, int8_t> { | ||
| 94 | + using ElementAccumulator = int32_t; | ||
| 95 | +}; | ||
| 96 | + | ||
| 97 | +template<> | ||
| 98 | +struct ElementAccumulatorSelector<bfloat16_t, bfloat16_t> { | ||
| 99 | + using ElementAccumulator = float; | ||
| 100 | +}; | ||
| 101 | + | ||
| 102 | + | ||
| 103 | +template<> | ||
| 104 | +struct ElementAccumulatorSelector<float8_e4m3_t, float8_e4m3_t> { | ||
| 105 | + using ElementAccumulator = float; | ||
| 106 | +}; | ||
| 107 | + | ||
| 108 | +template<> | ||
| 109 | +struct ElementAccumulatorSelector<float8_e5m2_t, float8_e5m2_t> { | ||
| 110 | + using ElementAccumulator = float; | ||
| 111 | +}; | ||
| 112 | + | ||
| 113 | +template<> | ||
| 114 | +struct ElementAccumulatorSelector<float8_e4m3_t, float8_e5m2_t> { | ||
| 115 | + using ElementAccumulator = float; | ||
| 116 | +}; | ||
| 117 | + | ||
| 118 | +template<> | ||
| 119 | +struct ElementAccumulatorSelector<float8_e5m2_t, float8_e4m3_t> { | ||
| 120 | + using ElementAccumulator = float; | ||
| 121 | +}; | ||
| 122 | + | ||
| 123 | + | ||
| 124 | +// template <class Element_, bool isMx = false> | ||
| 125 | +// struct GetL0Element { | ||
| 126 | +// using Element = Element_; | ||
| 127 | +// }; | ||
| 128 | +// #if defined(__NPU_ARCH__) && __NPU_ARCH__ == 3101 | ||
| 129 | +// template <> | ||
| 130 | +// struct GetL0Element<float8_e4m3_t, true> { | ||
| 131 | +// using Element = AscendC::mx_fp8_e4m3_t; | ||
| 132 | +// }; | ||
| 133 | + | ||
| 134 | +// template <> | ||
| 135 | +// struct GetL0Element<float8_e5m2_t, true> { | ||
| 136 | +// using Element = AscendC::mx_fp8_e5m2_t; | ||
| 137 | +// }; | ||
| 138 | +// #endif | ||
| 139 | + | ||
| 140 | +template<class GmAType> | ||
| 141 | +struct L1ATypeSelector { | ||
| 142 | + static_assert(DEPENDENT_FALSE<GmAType>, | ||
| 143 | + "Unsupported layout selector, can not find the specialization."); | ||
| 144 | +}; | ||
| 145 | + | ||
| 146 | +template<class Element> | ||
| 147 | +struct L1ATypeSelector<Gemm::GemmType<Element, layout::VectorLayout>> { | ||
| 148 | + using L1AType = Gemm::GemmType<Element, layout::VectorLayout, AscendC::TPosition::A1>; | ||
| 149 | +}; | ||
| 150 | + | ||
| 151 | +template<class Element> | ||
| 152 | +struct L1ATypeSelector<Gemm::GemmType<Element, layout::RowMajor>> { | ||
| 153 | + using L1AType = Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>; | ||
| 154 | +}; | ||
| 155 | + | ||
| 156 | +template<class Element> | ||
| 157 | +struct L1ATypeSelector<Gemm::GemmType<Element, layout::zN>> { | ||
| 158 | + using L1AType = Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>; | ||
| 159 | +}; | ||
| 160 | + | ||
| 161 | +template<class Element> | ||
| 162 | +struct L1ATypeSelector<Gemm::GemmType<Element, layout::PaddingRowMajor>> { | ||
| 163 | + using L1AType = Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>; | ||
| 164 | +}; | ||
| 165 | + | ||
| 166 | +template<class Element> | ||
| 167 | +struct L1ATypeSelector<Gemm::GemmType<Element, layout::ColumnMajor>> { | ||
| 168 | + using L1AType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>; | ||
| 169 | +}; | ||
| 170 | + | ||
| 171 | +template<class Element> | ||
| 172 | +struct L1ATypeSelector<Gemm::GemmType<Element, layout::nZ>> { | ||
| 173 | + using L1AType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>; | ||
| 174 | +}; | ||
| 175 | + | ||
| 176 | +template<class Element> | ||
| 177 | +struct L1ATypeSelector<Gemm::GemmType<Element, layout::PaddingColumnMajor>> { | ||
| 178 | + using L1AType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>; | ||
| 179 | +}; | ||
| 180 | + | ||
| 181 | +template<class GmBType> | ||
| 182 | +struct L1BTypeSelector { | ||
| 183 | + static_assert(DEPENDENT_FALSE<GmBType>, | ||
| 184 | + "Unsupported layout selector, can not find the specialization."); | ||
| 185 | +}; | ||
| 186 | + | ||
| 187 | +template<class Element> | ||
| 188 | +struct L1BTypeSelector<Gemm::GemmType<Element, layout::RowMajor>> { | ||
| 189 | + using L1BType = Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>; | ||
| 190 | +}; | ||
| 191 | + | ||
| 192 | +template<class Element> | ||
| 193 | +struct L1BTypeSelector<Gemm::GemmType<Element, layout::zN>> { | ||
| 194 | + using L1BType = Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>; | ||
| 195 | +}; | ||
| 196 | + | ||
| 197 | +template<class Element> | ||
| 198 | +struct L1BTypeSelector<Gemm::GemmType<Element, layout::PaddingRowMajor>> { | ||
| 199 | + using L1BType = Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>; | ||
| 200 | +}; | ||
| 201 | + | ||
| 202 | +template<class Element> | ||
| 203 | +struct L1BTypeSelector<Gemm::GemmType<Element, layout::ColumnMajor>> { | ||
| 204 | + using L1BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>; | ||
| 205 | +}; | ||
| 206 | + | ||
| 207 | +template<class Element> | ||
| 208 | +struct L1BTypeSelector<Gemm::GemmType<Element, layout::nZ>> { | ||
| 209 | + using L1BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>; | ||
| 210 | +}; | ||
| 211 | + | ||
| 212 | +template<class Element> | ||
| 213 | +struct L1BTypeSelector<Gemm::GemmType<Element, layout::PaddingColumnMajor>> { | ||
| 214 | + using L1BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>; | ||
| 215 | +}; | ||
| 216 | + | ||
| 217 | +template<class GmBiasType, class ElementAccumulator> | ||
| 218 | +struct L1BiasTypeSelector { | ||
| 219 | + static_assert(DEPENDENT_FALSE<GmBiasType>, | ||
| 220 | + "Unsupported layout selector, can not find the specialization."); | ||
| 221 | +}; | ||
| 222 | + | ||
| 223 | +template<class ArchTag> | ||
| 224 | +struct L0ALayoutSelector { | ||
| 225 | + static_assert(DEPENDENT_FALSE<ArchTag>, | ||
| 226 | + "Unsupported layout selector, can not find the specialization."); | ||
| 227 | +}; | ||
| 228 | + | ||
| 229 | +template<> | ||
| 230 | +struct L0ALayoutSelector<Arch::AtlasA2> { | ||
| 231 | + using Layout = layout::zZ; | ||
| 232 | +}; | ||
| 233 | + | ||
| 234 | +template<> | ||
| 235 | +struct L0ALayoutSelector<Arch::AtlasA5> { | ||
| 236 | + using Layout = layout::zN; | ||
| 237 | +}; | ||
| 238 | + | ||
| 239 | +template<class Element, class Layout, class Enable = void> | ||
| 240 | +struct L1AlignHelperTla { | ||
| 241 | + static_assert(DEPENDENT_FALSE<Element>, "Unsupported align helper tla, can not find the specialization."); | ||
| 242 | +}; | ||
| 243 | + | ||
| 244 | +template<class Element, class Layout> | ||
| 245 | +struct L1AlignHelperTla<Element, Layout, std::enable_if_t<tla::detail::isRowMajor<Layout>::value>> { | ||
| 246 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 247 | + static constexpr uint32_t M_ALIGNED = C0_NUM_PER_FRACTAL; | ||
| 248 | + static constexpr uint32_t K_ALIGNED = ELE_NUM_PER_C0; | ||
| 249 | + static constexpr uint32_t N_ALIGNED = ELE_NUM_PER_C0; | ||
| 250 | +}; | ||
| 251 | + | ||
| 252 | +template<class Element, class Layout> | ||
| 253 | +struct L1AlignHelperTla<Element, Layout, std::enable_if_t<tla::detail::isColumnMajor<Layout>::value>> { | ||
| 254 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 255 | + static constexpr uint32_t M_ALIGNED = ELE_NUM_PER_C0; | ||
| 256 | + static constexpr uint32_t K_ALIGNED = ELE_NUM_PER_C0; | ||
| 257 | + static constexpr uint32_t N_ALIGNED = C0_NUM_PER_FRACTAL; | ||
| 258 | +}; | ||
| 259 | + | ||
| 260 | +template<class ElementAccumulator> | ||
| 261 | +struct L1BiasTypeSelector<void, ElementAccumulator> { | ||
| 262 | + using GMBiasType = void; | ||
| 263 | + using L1BiasType = void; | ||
| 264 | + using L0BiasType = void; | ||
| 265 | +}; | ||
| 266 | + | ||
| 267 | +template<class Element, class ElementAccumulator> | ||
| 268 | +struct L1BiasTypeSelector<Gemm::GemmType<Element, layout::VectorLayout>, ElementAccumulator> { | ||
| 269 | + using GMBiasType = Gemm::GemmType<Element, layout::VectorLayout, AscendC::TPosition::GM>; | ||
| 270 | + using L1BiasType = Gemm::GemmType<Element, layout::VectorLayout, AscendC::TPosition::A1>; | ||
| 271 | + using L0BiasType = Gemm::GemmType<ElementAccumulator, layout::VectorLayout, AscendC::TPosition::C2>; | ||
| 272 | +}; | ||
| 273 | + | ||
| 274 | +/////////////////////////////////////// | ||
| 275 | +// new add | ||
| 276 | +template<> | ||
| 277 | +struct ElementAccumulatorSelector<int32_t, int32_t> { | ||
| 278 | + using ElementAccumulator = int32_t; | ||
| 279 | +}; | ||
| 280 | + | ||
| 281 | +template<class GmAType, class GmBType> | ||
| 282 | +struct L1AndL0TypeSelectorGemm{ | ||
| 283 | + static_assert(DEPENDENT_FALSE<GmAType>, | ||
| 284 | + "Unsupported layout selector, can not find the specialization."); | ||
| 285 | + static_assert(DEPENDENT_FALSE<GmBType>, | ||
| 286 | + "Unsupported layout selector, can not find the specialization."); | ||
| 287 | +}; | ||
| 288 | + | ||
| 289 | +template<class Element> | ||
| 290 | +struct L1AndL0TypeSelectorGemm<Gemm::GemmType<Element, layout::RowMajor>, Gemm::GemmType<Element, layout::RowMajor>>{ | ||
| 291 | + using L1AType = Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>; | ||
| 292 | + using L1BType = Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::B1>; | ||
| 293 | + using L0AType = Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::A2>; | ||
| 294 | + using L0BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B2>; | ||
| 295 | +}; | ||
| 296 | + | ||
| 297 | +template<> | ||
| 298 | +struct L1AndL0TypeSelectorGemm<Gemm::GemmType<int8_t, layout::RowMajor>, Gemm::GemmType<int8_t, layout::RowMajor>>{ | ||
| 299 | + using L1AType = Gemm::GemmType<int8_t, layout::zN, AscendC::TPosition::A1>; | ||
| 300 | + using L1BType = Gemm::GemmType<int8_t, layout::zN, AscendC::TPosition::B1>; | ||
| 301 | + using L0AType = Gemm::GemmType<int8_t, layout::zZ, AscendC::TPosition::A2>; | ||
| 302 | + using L0BType = Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::B2>; | ||
| 303 | +}; | ||
| 304 | + | ||
| 305 | +template<class Element> | ||
| 306 | +struct L1AndL0TypeSelectorGemm<Gemm::GemmType<Element, layout::ColumnMajor>, Gemm::GemmType<Element, layout::ColumnMajor>>{ | ||
| 307 | + using L1AType = Gemm::GemmType<Element, layout::nN, AscendC::TPosition::A1>; | ||
| 308 | + using L1BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B1>; | ||
| 309 | + using L0AType = Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::A2>; | ||
| 310 | + using L0BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B2>; | ||
| 311 | +}; | ||
| 312 | + | ||
| 313 | +template<> | ||
| 314 | +struct L1AndL0TypeSelectorGemm<Gemm::GemmType<int8_t, layout::ColumnMajor>, Gemm::GemmType<int8_t, layout::ColumnMajor>>{ | ||
| 315 | + using L1AType = Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::A1>; | ||
| 316 | + using L1BType = Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::B1>; | ||
| 317 | + using L0AType = Gemm::GemmType<int8_t, layout::zZ, AscendC::TPosition::A2>; | ||
| 318 | + using L0BType = Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::B2>; | ||
| 319 | +}; | ||
| 320 | + | ||
| 321 | +template<class Element> | ||
| 322 | +struct L1AndL0TypeSelectorGemm<Gemm::GemmType<Element, layout::RowMajor>, Gemm::GemmType<Element, layout::ColumnMajor>>{ | ||
| 323 | + using L1AType = Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>; | ||
| 324 | + using L1BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B1>; | ||
| 325 | + using L0AType = Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::A2>; | ||
| 326 | + using L0BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B2>; | ||
| 327 | +}; | ||
| 328 | + | ||
| 329 | +template<class Element> | ||
| 330 | +struct L1AndL0TypeSelectorGemm<Gemm::GemmType<Element, layout::ColumnMajor>, Gemm::GemmType<Element, layout::RowMajor>>{ | ||
| 331 | + using L1AType = Gemm::GemmType<Element, layout::nN, AscendC::TPosition::A1>; | ||
| 332 | + using L1BType = Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::B1>; | ||
| 333 | + using L0AType = Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::A2>; | ||
| 334 | + using L0BType = Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B2>; | ||
| 335 | +}; | ||
| 336 | + | ||
| 337 | +template<> | ||
| 338 | +struct L1AndL0TypeSelectorGemm<Gemm::GemmType<int8_t, layout::ColumnMajor>, Gemm::GemmType<int8_t, layout::RowMajor>>{ | ||
| 339 | + using L1AType = Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::A1>; | ||
| 340 | + using L1BType = Gemm::GemmType<int8_t, layout::zN, AscendC::TPosition::B1>; | ||
| 341 | + using L0AType = Gemm::GemmType<int8_t, layout::zZ, AscendC::TPosition::A2>; | ||
| 342 | + using L0BType = Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::B2>; | ||
| 343 | +}; | ||
| 344 | +/////////////////////////////////////// | ||
| 345 | +} // namespace NpuArch::Gemm::helper | ||
| 346 | + | ||
| 347 | + | ||
| @@ -0,0 +1,1068 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace NpuArch::Gemm::Tile { | ||
| 22 | + | ||
| 23 | +template < | ||
| 24 | + class ArchTag, | ||
| 25 | + /// GemmType for matrix operand | ||
| 26 | + class GmType, | ||
| 27 | + class L1Type = void | ||
| 28 | +> | ||
| 29 | +struct CopyGmToL1 { | ||
| 30 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy gm to l1, can not find the specialization."); | ||
| 31 | +}; | ||
| 32 | + | ||
| 33 | +template < | ||
| 34 | + class ArchTag, | ||
| 35 | + /// GemmType for matrix operand | ||
| 36 | + class GmType, | ||
| 37 | + class L1Type = void | ||
| 38 | +> | ||
| 39 | +struct CopyGmToL1IntervalDataCopy { | ||
| 40 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy gm to l1, can not find the specialization."); | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +//////////////////////////////////////// | ||
| 44 | +/// Using the standard strided DataCopy interface to implement nd2nz | ||
| 45 | +/// transfer may achieve higher data transfer efficiency when the data block shape is short and wide | ||
| 46 | +/// Partial specialization for AtlasA2, half, RowMajor in and zN out. | ||
| 47 | +template<> | ||
| 48 | +struct CopyGmToL1IntervalDataCopy<Arch::AtlasA2, Gemm::GemmType<half, layout::RowMajor>> { | ||
| 49 | + using LayoutDst = layout::zN; | ||
| 50 | + using LayoutSrc = layout::RowMajor; | ||
| 51 | + using Element = half; | ||
| 52 | + | ||
| 53 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 54 | + | ||
| 55 | + // Mehtods | ||
| 56 | + | ||
| 57 | + __aicore__ inline | ||
| 58 | + CopyGmToL1IntervalDataCopy() {}; | ||
| 59 | + | ||
| 60 | + __aicore__ inline | ||
| 61 | + void operator()( | ||
| 62 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 63 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 64 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 65 | + { | ||
| 66 | + for (int i = 0; i < layoutSrc.shape(0); ++i) { | ||
| 67 | + AscendC::DataCopyParams dataCopyParams( | ||
| 68 | + CeilDiv(layoutSrc.shape(1), layoutDst.shape(2)), | ||
| 69 | + layoutDst.shape(2) / ELE_NUM_PER_C0, | ||
| 70 | + 0, | ||
| 71 | + (layoutDst.stride(3) - layoutDst.shape(2)) / ELE_NUM_PER_C0 | ||
| 72 | + ); | ||
| 73 | + AscendC::DataCopy(dstTensor[i * layoutDst.shape(2)], srcTensor[i * layoutSrc.stride(0)], dataCopyParams); | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | +}; | ||
| 77 | + | ||
| 78 | +/// Partial specialization for AtlasA2, half, PaddingRowMajor in and zN out. | ||
| 79 | +/// Using the standard strided DataCopy interface to implement nd2nz | ||
| 80 | +/// transfer may achieve higher data transfer efficiency when the data block shape is short and wide | ||
| 81 | +template<> | ||
| 82 | +struct CopyGmToL1IntervalDataCopy<Arch::AtlasA2, Gemm::GemmType<half, layout::PaddingRowMajor>> { | ||
| 83 | + using LayoutDst = layout::zN; | ||
| 84 | + using LayoutSrc = layout::PaddingRowMajor; | ||
| 85 | + using Element = half; | ||
| 86 | + | ||
| 87 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 88 | + | ||
| 89 | + // Mehtods | ||
| 90 | + | ||
| 91 | + __aicore__ inline | ||
| 92 | + CopyGmToL1IntervalDataCopy() {}; | ||
| 93 | + | ||
| 94 | + __aicore__ inline | ||
| 95 | + void operator()( | ||
| 96 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 97 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 98 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 99 | + { | ||
| 100 | + for (int i = 0; i < layoutSrc.orgShape(0); ++i) { | ||
| 101 | + AscendC::DataCopyParams dataCopyParams( | ||
| 102 | + CeilDiv(layoutSrc.orgShape(1), layoutDst.shape(2)), | ||
| 103 | + layoutDst.shape(2) / ELE_NUM_PER_C0, | ||
| 104 | + 0, | ||
| 105 | + (layoutDst.stride(3) - layoutDst.shape(2)) / ELE_NUM_PER_C0 | ||
| 106 | + ); | ||
| 107 | + AscendC::DataCopy(dstTensor[i * layoutDst.shape(2)], srcTensor[i * layoutSrc.stride(0)], dataCopyParams); | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | +}; | ||
| 111 | + | ||
| 112 | +/// Partial specialization for AtlasA2, half, ColumnMajor in and zN out. | ||
| 113 | +/// Using the standard strided DataCopy interface to implement nd2nz | ||
| 114 | +/// transfer may achieve higher data transfer efficiency when the data block shape is tall and narrow | ||
| 115 | +template<> | ||
| 116 | +struct CopyGmToL1IntervalDataCopy<Arch::AtlasA2, Gemm::GemmType<half, layout::ColumnMajor>> { | ||
| 117 | + using LayoutDst = layout::nZ; | ||
| 118 | + using LayoutSrc = layout::ColumnMajor; | ||
| 119 | + using Element = half; | ||
| 120 | + | ||
| 121 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 122 | + | ||
| 123 | + // Mehtods | ||
| 124 | + | ||
| 125 | + __aicore__ inline | ||
| 126 | + CopyGmToL1IntervalDataCopy() {}; | ||
| 127 | + | ||
| 128 | + __aicore__ inline | ||
| 129 | + void operator()( | ||
| 130 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 131 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 132 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 133 | + { | ||
| 134 | + for (int i = 0; i < layoutSrc.shape(1); ++i) { | ||
| 135 | + AscendC::DataCopyParams dataCopyParams( | ||
| 136 | + CeilDiv(layoutSrc.shape(0), layoutDst.shape(0)), | ||
| 137 | + layoutDst.shape(0) / ELE_NUM_PER_C0, | ||
| 138 | + 0, | ||
| 139 | + (layoutDst.stride(1) - layoutDst.shape(0)) / ELE_NUM_PER_C0 | ||
| 140 | + ); | ||
| 141 | + AscendC::DataCopy(dstTensor[i * layoutDst.shape(0)], srcTensor[i * layoutSrc.stride(1)], dataCopyParams); | ||
| 142 | + } | ||
| 143 | + } | ||
| 144 | +}; | ||
| 145 | + | ||
| 146 | +/// Partial specialization for AtlasA2, half, PaddingColumnMajor in and zN out. | ||
| 147 | +/// Using the standard strided DataCopy interface to implement nd2nz | ||
| 148 | +/// transfer may achieve higher data transfer efficiency when the data block shape is tall and narrow | ||
| 149 | +template<> | ||
| 150 | +struct CopyGmToL1IntervalDataCopy<Arch::AtlasA2, Gemm::GemmType<half, layout::PaddingColumnMajor>> { | ||
| 151 | + using LayoutDst = layout::nZ; | ||
| 152 | + using LayoutSrc = layout::PaddingColumnMajor; | ||
| 153 | + using Element = half; | ||
| 154 | + | ||
| 155 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 156 | + | ||
| 157 | + // Mehtods | ||
| 158 | + | ||
| 159 | + __aicore__ inline | ||
| 160 | + CopyGmToL1IntervalDataCopy() {}; | ||
| 161 | + | ||
| 162 | + __aicore__ inline | ||
| 163 | + void operator()( | ||
| 164 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 165 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 166 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 167 | + { | ||
| 168 | + for (int i = 0; i < layoutSrc.orgShape(1); ++i) { | ||
| 169 | + AscendC::DataCopyParams dataCopyParams( | ||
| 170 | + CeilDiv(layoutSrc.orgShape(0), layoutDst.shape(0)), | ||
| 171 | + layoutDst.shape(0) / ELE_NUM_PER_C0, | ||
| 172 | + 0, | ||
| 173 | + (layoutDst.stride(1) - layoutDst.shape(0)) / ELE_NUM_PER_C0 | ||
| 174 | + ); | ||
| 175 | + AscendC::DataCopy(dstTensor[i * layoutDst.shape(0)], srcTensor[i * layoutSrc.stride(2)], dataCopyParams); | ||
| 176 | + } | ||
| 177 | + } | ||
| 178 | +}; | ||
| 179 | + | ||
| 180 | +/// new add gemm | ||
| 181 | +template <class ArchTag, class Element> | ||
| 182 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::RowMajor>, Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>> { | ||
| 183 | + using LayoutDst = layout::zN; | ||
| 184 | + using LayoutSrc = layout::RowMajor; | ||
| 185 | + | ||
| 186 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 187 | + | ||
| 188 | + // Mehtods | ||
| 189 | + | ||
| 190 | + __aicore__ inline | ||
| 191 | + CopyGmToL1() {}; | ||
| 192 | + | ||
| 193 | + __aicore__ inline | ||
| 194 | + void operator()( | ||
| 195 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 196 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 197 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 198 | + { | ||
| 199 | + AscendC::Nd2NzParams intriParams; | ||
| 200 | + | ||
| 201 | + intriParams.ndNum = 1; | ||
| 202 | + intriParams.dValue = layoutSrc.shape(1); | ||
| 203 | + intriParams.srcNdMatrixStride = 0; | ||
| 204 | + intriParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 205 | + intriParams.dstNzMatrixStride = 0; | ||
| 206 | + | ||
| 207 | + if (layoutSrc.stride(0) < STRIDE_LIMIT) { | ||
| 208 | + intriParams.nValue = layoutSrc.shape(0); | ||
| 209 | + intriParams.srcDValue = layoutSrc.stride(0); | ||
| 210 | + intriParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 211 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 212 | + } else { | ||
| 213 | + intriParams.nValue = 1; | ||
| 214 | + intriParams.srcDValue = 0; | ||
| 215 | + intriParams.dstNzNStride = 0; | ||
| 216 | + for (uint32_t i = 0; i < layoutSrc.shape(0); i++) { | ||
| 217 | + AscendC::DataCopy(dstTensor[i * ELE_NUM_PER_C0], srcTensor[i * layoutSrc.stride(0)], intriParams); | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + } | ||
| 221 | +}; | ||
| 222 | + | ||
| 223 | +template <class ArchTag, class Element> | ||
| 224 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::RowMajor>, Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::B1>> { | ||
| 225 | + using LayoutDst = layout::zZ; | ||
| 226 | + using LayoutSrc = layout::RowMajor; | ||
| 227 | + | ||
| 228 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 229 | + | ||
| 230 | + // Mehtods | ||
| 231 | + | ||
| 232 | + __aicore__ inline | ||
| 233 | + CopyGmToL1() {}; | ||
| 234 | + | ||
| 235 | + __aicore__ inline | ||
| 236 | + void operator()( | ||
| 237 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 238 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 239 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 240 | + { | ||
| 241 | + AscendC::Nd2NzParams intriParams; | ||
| 242 | + uint32_t srcNdStride = C0_NUM_PER_FRACTAL * layoutSrc.stride(0); | ||
| 243 | + uint32_t ndNum = layoutSrc.shape(0) / C0_NUM_PER_FRACTAL; | ||
| 244 | + uint32_t remains = layoutSrc.shape(0) % C0_NUM_PER_FRACTAL; | ||
| 245 | + if (srcNdStride < STRIDE_LIMIT) { | ||
| 246 | + if (ndNum) { | ||
| 247 | + intriParams.ndNum = ndNum; | ||
| 248 | + intriParams.nValue = C0_NUM_PER_FRACTAL; | ||
| 249 | + intriParams.dValue = layoutSrc.shape(1); | ||
| 250 | + intriParams.srcNdMatrixStride = srcNdStride; | ||
| 251 | + intriParams.srcDValue = layoutSrc.stride(0); | ||
| 252 | + | ||
| 253 | + intriParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 254 | + intriParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 255 | + | ||
| 256 | + intriParams.dstNzMatrixStride = layoutDst.stride(1); | ||
| 257 | + | ||
| 258 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | + if (remains) { | ||
| 262 | + AscendC::Nd2NzParams tailParams; | ||
| 263 | + tailParams.ndNum = 1; | ||
| 264 | + tailParams.nValue = remains; | ||
| 265 | + tailParams.dValue = layoutSrc.shape(1); | ||
| 266 | + tailParams.srcNdMatrixStride = srcNdStride; | ||
| 267 | + tailParams.srcDValue = layoutSrc.stride(0); | ||
| 268 | + | ||
| 269 | + tailParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 270 | + tailParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 271 | + tailParams.dstNzMatrixStride = 0; //` | ||
| 272 | + | ||
| 273 | + AscendC::DataCopy(dstTensor[ndNum * layoutDst.stride(1)], srcTensor[ndNum * srcNdStride], tailParams); | ||
| 274 | + } | ||
| 275 | + } else if (layoutSrc.stride(0) < STRIDE_LIMIT) { | ||
| 276 | + for (uint32_t i = 0; i < ndNum; i++) { | ||
| 277 | + AscendC::Nd2NzParams intriParams; | ||
| 278 | + intriParams.ndNum = 1; | ||
| 279 | + intriParams.nValue = C0_NUM_PER_FRACTAL; | ||
| 280 | + intriParams.dValue = layoutSrc.shape(1); | ||
| 281 | + intriParams.srcNdMatrixStride = 0; | ||
| 282 | + intriParams.srcDValue = layoutSrc.stride(0); | ||
| 283 | + | ||
| 284 | + intriParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 285 | + intriParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 286 | + intriParams.dstNzMatrixStride = 0; | ||
| 287 | + | ||
| 288 | + AscendC::DataCopy(dstTensor[i * layoutDst.stride(1)], srcTensor[i * srcNdStride], intriParams); | ||
| 289 | + } | ||
| 290 | + if (remains) { | ||
| 291 | + AscendC::Nd2NzParams tailParams; | ||
| 292 | + tailParams.ndNum = 1; | ||
| 293 | + tailParams.nValue = remains; | ||
| 294 | + tailParams.dValue = layoutSrc.shape(1); | ||
| 295 | + tailParams.srcNdMatrixStride = 0; | ||
| 296 | + tailParams.srcDValue = layoutSrc.stride(0); | ||
| 297 | + | ||
| 298 | + tailParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 299 | + tailParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 300 | + tailParams.dstNzMatrixStride = 0; | ||
| 301 | + | ||
| 302 | + AscendC::DataCopy(dstTensor[ndNum * layoutDst.stride(1)], srcTensor[ndNum * srcNdStride], tailParams); | ||
| 303 | + } | ||
| 304 | + } else { | ||
| 305 | + for (uint32_t i = 0; i < layoutSrc.shape(0); i++) { | ||
| 306 | + uint32_t idxR0 = i / C0_NUM_PER_FRACTAL; | ||
| 307 | + uint32_t idxInR0 = i % C0_NUM_PER_FRACTAL; | ||
| 308 | + | ||
| 309 | + AscendC::Nd2NzParams intriParams; | ||
| 310 | + intriParams.ndNum = 1; | ||
| 311 | + intriParams.nValue = 1; | ||
| 312 | + intriParams.dValue = layoutSrc.shape(1); | ||
| 313 | + intriParams.srcNdMatrixStride = 0; | ||
| 314 | + intriParams.srcDValue = 0; | ||
| 315 | + | ||
| 316 | + intriParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 317 | + intriParams.dstNzNStride = 0; | ||
| 318 | + intriParams.dstNzMatrixStride = 0; | ||
| 319 | + | ||
| 320 | + uint32_t offsetDst = i * idxR0 * layoutDst.stride(1) + idxInR0 * ELE_NUM_PER_C0; | ||
| 321 | + uint32_t offsetSrc = i * layoutSrc.stride(0); | ||
| 322 | + AscendC::DataCopy(dstTensor[offsetDst], srcTensor[offsetSrc], intriParams); | ||
| 323 | + } | ||
| 324 | + } | ||
| 325 | + } | ||
| 326 | +}; | ||
| 327 | + | ||
| 328 | +template <class ArchTag, class Element> | ||
| 329 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::ColumnMajor>, Gemm::GemmType<Element, layout::nN, AscendC::TPosition::A1>> { | ||
| 330 | + using LayoutDst = layout::nN; | ||
| 331 | + using LayoutSrc = layout::ColumnMajor; | ||
| 332 | + | ||
| 333 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 334 | + | ||
| 335 | + // Mehtods | ||
| 336 | + | ||
| 337 | + __aicore__ inline | ||
| 338 | + CopyGmToL1() {}; | ||
| 339 | + | ||
| 340 | + __aicore__ inline | ||
| 341 | + void operator()( | ||
| 342 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 343 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 344 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 345 | + { | ||
| 346 | + AscendC::Nd2NzParams intriParams; | ||
| 347 | + uint32_t srcNdStride = C0_NUM_PER_FRACTAL * layoutSrc.stride(1); | ||
| 348 | + uint32_t ndNum = layoutSrc.shape(1) / C0_NUM_PER_FRACTAL; | ||
| 349 | + uint32_t remains = layoutSrc.shape(1) % C0_NUM_PER_FRACTAL; | ||
| 350 | + if (srcNdStride < STRIDE_LIMIT) { | ||
| 351 | + if (ndNum) { | ||
| 352 | + intriParams.ndNum = ndNum; | ||
| 353 | + intriParams.nValue = C0_NUM_PER_FRACTAL; | ||
| 354 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 355 | + intriParams.srcNdMatrixStride = srcNdStride; | ||
| 356 | + intriParams.srcDValue = layoutSrc.stride(1); | ||
| 357 | + | ||
| 358 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 359 | + intriParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 360 | + | ||
| 361 | + intriParams.dstNzMatrixStride = layoutDst.stride(3); | ||
| 362 | + | ||
| 363 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 364 | + } | ||
| 365 | + | ||
| 366 | + if (remains) { | ||
| 367 | + AscendC::Nd2NzParams tailParams; | ||
| 368 | + tailParams.ndNum = 1; | ||
| 369 | + tailParams.nValue = remains; | ||
| 370 | + tailParams.dValue = layoutSrc.shape(0); | ||
| 371 | + tailParams.srcNdMatrixStride = srcNdStride; | ||
| 372 | + tailParams.srcDValue = layoutSrc.stride(1); | ||
| 373 | + | ||
| 374 | + tailParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 375 | + tailParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 376 | + tailParams.dstNzMatrixStride = 0; | ||
| 377 | + | ||
| 378 | + AscendC::DataCopy(dstTensor[ndNum * layoutDst.stride(3)], srcTensor[ndNum * srcNdStride], tailParams); | ||
| 379 | + } | ||
| 380 | + } else if (layoutSrc.stride(1) < STRIDE_LIMIT) { | ||
| 381 | + for (uint32_t i = 0; i < ndNum; i++) { | ||
| 382 | + AscendC::Nd2NzParams intriParams; | ||
| 383 | + intriParams.ndNum = 1; | ||
| 384 | + intriParams.nValue = C0_NUM_PER_FRACTAL; | ||
| 385 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 386 | + intriParams.srcNdMatrixStride = 0; | ||
| 387 | + intriParams.srcDValue = layoutSrc.stride(1); | ||
| 388 | + | ||
| 389 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 390 | + intriParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 391 | + intriParams.dstNzMatrixStride = 0; | ||
| 392 | + | ||
| 393 | + AscendC::DataCopy(dstTensor[i * layoutDst.stride(3)], srcTensor[i * srcNdStride], intriParams); | ||
| 394 | + } | ||
| 395 | + if (remains) { | ||
| 396 | + AscendC::Nd2NzParams tailParams; | ||
| 397 | + tailParams.ndNum = 1; | ||
| 398 | + tailParams.nValue = remains; | ||
| 399 | + tailParams.dValue = layoutSrc.shape(0); | ||
| 400 | + tailParams.srcNdMatrixStride = 0; | ||
| 401 | + tailParams.srcDValue = layoutSrc.stride(1); | ||
| 402 | + | ||
| 403 | + tailParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 404 | + tailParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 405 | + tailParams.dstNzMatrixStride = 0; | ||
| 406 | + | ||
| 407 | + AscendC::DataCopy(dstTensor[ndNum * layoutDst.stride(3)], srcTensor[ndNum * srcNdStride], tailParams); | ||
| 408 | + } | ||
| 409 | + } else { | ||
| 410 | + for (uint32_t i = 0; i < layoutSrc.shape(1); i++) { | ||
| 411 | + uint32_t idxR0 = i / C0_NUM_PER_FRACTAL; | ||
| 412 | + uint32_t idxInR0 = i % C0_NUM_PER_FRACTAL; | ||
| 413 | + | ||
| 414 | + AscendC::Nd2NzParams intriParams; | ||
| 415 | + intriParams.ndNum = 1; | ||
| 416 | + intriParams.nValue = 1; | ||
| 417 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 418 | + intriParams.srcNdMatrixStride = 0; | ||
| 419 | + intriParams.srcDValue = 0; | ||
| 420 | + | ||
| 421 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 422 | + intriParams.dstNzNStride = 0; | ||
| 423 | + intriParams.dstNzMatrixStride = 0; | ||
| 424 | + | ||
| 425 | + uint32_t offsetDst = i * idxR0 * layoutDst.stride(3) + idxInR0 * ELE_NUM_PER_C0; | ||
| 426 | + uint32_t offsetSrc = i * layoutSrc.stride(1); | ||
| 427 | + AscendC::DataCopy(dstTensor[offsetDst], srcTensor[offsetSrc], intriParams); | ||
| 428 | + } | ||
| 429 | + } | ||
| 430 | + } | ||
| 431 | +}; | ||
| 432 | + | ||
| 433 | +template <class ArchTag, class Element> | ||
| 434 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::ColumnMajor>, Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B1>> { | ||
| 435 | + using LayoutDst = layout::nZ; | ||
| 436 | + using LayoutSrc = layout::ColumnMajor; | ||
| 437 | + | ||
| 438 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 439 | + | ||
| 440 | + // Mehtods | ||
| 441 | + | ||
| 442 | + __aicore__ inline | ||
| 443 | + CopyGmToL1() {}; | ||
| 444 | + | ||
| 445 | + __aicore__ inline | ||
| 446 | + void operator()( | ||
| 447 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 448 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 449 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 450 | + { | ||
| 451 | + AscendC::Nd2NzParams intriParams; | ||
| 452 | + | ||
| 453 | + intriParams.ndNum = 1; | ||
| 454 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 455 | + intriParams.srcNdMatrixStride = 0; | ||
| 456 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 457 | + intriParams.dstNzMatrixStride = 0; | ||
| 458 | + | ||
| 459 | + if (layoutSrc.stride(1) < STRIDE_LIMIT) { | ||
| 460 | + intriParams.nValue = layoutSrc.shape(1); | ||
| 461 | + intriParams.srcDValue = layoutSrc.stride(1); | ||
| 462 | + intriParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 463 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 464 | + } else { | ||
| 465 | + intriParams.nValue = 1; | ||
| 466 | + intriParams.srcDValue = 0; | ||
| 467 | + intriParams.dstNzNStride = 0; | ||
| 468 | + for (uint32_t i = 0; i < layoutSrc.shape(1); i++) { | ||
| 469 | + AscendC::DataCopy(dstTensor[i * ELE_NUM_PER_C0], srcTensor[i * layoutSrc.stride(1)], intriParams); | ||
| 470 | + } | ||
| 471 | + } | ||
| 472 | + } | ||
| 473 | +}; | ||
| 474 | + | ||
| 475 | +template <class ArchTag, class Element> | ||
| 476 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::ColumnMajor>, Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>> { | ||
| 477 | + using LayoutDst = layout::nZ; | ||
| 478 | + using LayoutSrc = layout::ColumnMajor; | ||
| 479 | + | ||
| 480 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 481 | + | ||
| 482 | + // Mehtods | ||
| 483 | + | ||
| 484 | + __aicore__ inline | ||
| 485 | + CopyGmToL1() {}; | ||
| 486 | + | ||
| 487 | + __aicore__ inline | ||
| 488 | + void operator()( | ||
| 489 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 490 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 491 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 492 | + { | ||
| 493 | + AscendC::Nd2NzParams intriParams; | ||
| 494 | + | ||
| 495 | + intriParams.ndNum = 1; | ||
| 496 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 497 | + intriParams.srcNdMatrixStride = 0; | ||
| 498 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 499 | + intriParams.dstNzMatrixStride = 0; | ||
| 500 | + | ||
| 501 | + if (layoutSrc.stride(1) < STRIDE_LIMIT) { | ||
| 502 | + intriParams.nValue = layoutSrc.shape(1); | ||
| 503 | + intriParams.srcDValue = layoutSrc.stride(1); | ||
| 504 | + intriParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 505 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 506 | + } else { | ||
| 507 | + intriParams.nValue = 1; | ||
| 508 | + intriParams.srcDValue = 0; | ||
| 509 | + intriParams.dstNzNStride = 0; | ||
| 510 | + for (uint32_t i = 0; i < layoutSrc.shape(1); i++) { | ||
| 511 | + AscendC::DataCopy(dstTensor[i * ELE_NUM_PER_C0], srcTensor[i * layoutSrc.stride(1)], intriParams); | ||
| 512 | + } | ||
| 513 | + } | ||
| 514 | + } | ||
| 515 | +}; | ||
| 516 | +//////////////////////////////////////// | ||
| 517 | + | ||
| 518 | +/////////////////////////////////////// | ||
| 519 | +/// new add gemv, VectorLayout -> zN | ||
| 520 | +template <class ArchTag, class Element> | ||
| 521 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::VectorLayout>, Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>> { | ||
| 522 | + using LayoutDst = layout::zN; | ||
| 523 | + using LayoutSrc = layout::VectorLayout; | ||
| 524 | + | ||
| 525 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 526 | + | ||
| 527 | + // Methods | ||
| 528 | + | ||
| 529 | + __aicore__ inline | ||
| 530 | + CopyGmToL1() {}; | ||
| 531 | + | ||
| 532 | + __aicore__ inline | ||
| 533 | + void operator()( | ||
| 534 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 535 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 536 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 537 | + { | ||
| 538 | + AscendC::Nd2NzParams intriParams; | ||
| 539 | + | ||
| 540 | + intriParams.ndNum = 1; | ||
| 541 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 542 | + intriParams.srcNdMatrixStride = 0; | ||
| 543 | + intriParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 544 | + intriParams.dstNzMatrixStride = 0; | ||
| 545 | + intriParams.nValue = 1; | ||
| 546 | + intriParams.srcDValue = layoutSrc.shape(0); | ||
| 547 | + intriParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 548 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 549 | + } | ||
| 550 | +}; | ||
| 551 | + | ||
| 552 | + | ||
| 553 | + | ||
| 554 | +/////////////////////////////////////// | ||
| 555 | +/// new add gemv, ColumnMajor -> nN | ||
| 556 | +template <class ArchTag, class Element> | ||
| 557 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::ColumnMajor>, Gemm::GemmType<Element, layout::nN, AscendC::TPosition::B1>> { | ||
| 558 | + using LayoutDst = layout::nN; | ||
| 559 | + using LayoutSrc = layout::ColumnMajor; | ||
| 560 | + | ||
| 561 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 562 | + | ||
| 563 | + // Methods | ||
| 564 | + | ||
| 565 | + __aicore__ inline | ||
| 566 | + CopyGmToL1() {}; | ||
| 567 | + | ||
| 568 | + __aicore__ inline | ||
| 569 | + void operator()( | ||
| 570 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 571 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 572 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 573 | + { | ||
| 574 | + AscendC::Nd2NzParams intriParams; | ||
| 575 | + uint32_t srcNdStride = C0_NUM_PER_FRACTAL * layoutSrc.stride(1); | ||
| 576 | + uint32_t ndNum = layoutSrc.shape(1) / C0_NUM_PER_FRACTAL; | ||
| 577 | + uint32_t remains = layoutSrc.shape(1) % C0_NUM_PER_FRACTAL; | ||
| 578 | + if (srcNdStride < STRIDE_LIMIT) { | ||
| 579 | + if (ndNum) { | ||
| 580 | + intriParams.ndNum = ndNum; | ||
| 581 | + intriParams.nValue = C0_NUM_PER_FRACTAL; | ||
| 582 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 583 | + intriParams.srcNdMatrixStride = srcNdStride; | ||
| 584 | + intriParams.srcDValue = layoutSrc.stride(1); | ||
| 585 | + | ||
| 586 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 587 | + intriParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 588 | + | ||
| 589 | + intriParams.dstNzMatrixStride = layoutDst.stride(3); | ||
| 590 | + | ||
| 591 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 592 | + } | ||
| 593 | + | ||
| 594 | + if (remains) { | ||
| 595 | + AscendC::Nd2NzParams tailParams; | ||
| 596 | + tailParams.ndNum = 1; | ||
| 597 | + tailParams.nValue = remains; | ||
| 598 | + tailParams.dValue = layoutSrc.shape(0); | ||
| 599 | + tailParams.srcNdMatrixStride = srcNdStride; | ||
| 600 | + tailParams.srcDValue = layoutSrc.stride(1); | ||
| 601 | + | ||
| 602 | + tailParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 603 | + tailParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 604 | + tailParams.dstNzMatrixStride = 0; | ||
| 605 | + | ||
| 606 | + AscendC::DataCopy(dstTensor[ndNum * layoutDst.stride(3)], srcTensor[ndNum * srcNdStride], tailParams); | ||
| 607 | + } | ||
| 608 | + } else if (layoutSrc.stride(1) < STRIDE_LIMIT) { | ||
| 609 | + for (uint32_t i = 0; i < ndNum; i++) { | ||
| 610 | + AscendC::Nd2NzParams intriParams; | ||
| 611 | + intriParams.ndNum = 1; | ||
| 612 | + intriParams.nValue = C0_NUM_PER_FRACTAL; | ||
| 613 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 614 | + intriParams.srcNdMatrixStride = 0; | ||
| 615 | + intriParams.srcDValue = layoutSrc.stride(1); | ||
| 616 | + | ||
| 617 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 618 | + intriParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 619 | + intriParams.dstNzMatrixStride = 0; | ||
| 620 | + | ||
| 621 | + AscendC::DataCopy(dstTensor[i * layoutDst.stride(3)], srcTensor[i * srcNdStride], intriParams); | ||
| 622 | + } | ||
| 623 | + if (remains) { | ||
| 624 | + AscendC::Nd2NzParams tailParams; | ||
| 625 | + tailParams.ndNum = 1; | ||
| 626 | + tailParams.nValue = remains; | ||
| 627 | + tailParams.dValue = layoutSrc.shape(0); | ||
| 628 | + tailParams.srcNdMatrixStride = 0; | ||
| 629 | + tailParams.srcDValue = layoutSrc.stride(1); | ||
| 630 | + | ||
| 631 | + tailParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 632 | + tailParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 633 | + tailParams.dstNzMatrixStride = 0; | ||
| 634 | + | ||
| 635 | + AscendC::DataCopy(dstTensor[ndNum * layoutDst.stride(3)], srcTensor[ndNum * srcNdStride], tailParams); | ||
| 636 | + } | ||
| 637 | + } else { | ||
| 638 | + for (uint32_t i = 0; i < layoutSrc.shape(1); i++) { | ||
| 639 | + uint32_t idxR0 = i / C0_NUM_PER_FRACTAL; | ||
| 640 | + uint32_t idxInR0 = i % C0_NUM_PER_FRACTAL; | ||
| 641 | + | ||
| 642 | + AscendC::Nd2NzParams intriParams; | ||
| 643 | + intriParams.ndNum = 1; | ||
| 644 | + intriParams.nValue = 1; | ||
| 645 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 646 | + intriParams.srcNdMatrixStride = 0; | ||
| 647 | + intriParams.srcDValue = 0; | ||
| 648 | + | ||
| 649 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 650 | + intriParams.dstNzNStride = 0; | ||
| 651 | + intriParams.dstNzMatrixStride = 0; | ||
| 652 | + | ||
| 653 | + uint32_t offsetDst = i * idxR0 * layoutDst.stride(3) + idxInR0 * ELE_NUM_PER_C0; | ||
| 654 | + uint32_t offsetSrc = i * layoutSrc.stride(1); | ||
| 655 | + AscendC::DataCopy(dstTensor[offsetDst], srcTensor[offsetSrc], intriParams); | ||
| 656 | + } | ||
| 657 | + } | ||
| 658 | + } | ||
| 659 | +}; | ||
| 660 | + | ||
| 661 | +template <class ArchTag, class Element> | ||
| 662 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::RowMajor>, Gemm::GemmType<Element, layout::zN, AscendC::TPosition::B1>> { | ||
| 663 | + using LayoutDst = layout::zN; | ||
| 664 | + using LayoutSrc = layout::RowMajor; | ||
| 665 | + | ||
| 666 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 667 | + | ||
| 668 | + // Methods | ||
| 669 | + | ||
| 670 | + __aicore__ inline | ||
| 671 | + CopyGmToL1() {}; | ||
| 672 | + | ||
| 673 | + __aicore__ inline | ||
| 674 | + void operator()( | ||
| 675 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 676 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 677 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 678 | + { | ||
| 679 | + AscendC::Nd2NzParams intriParams; | ||
| 680 | + | ||
| 681 | + intriParams.ndNum = 1; | ||
| 682 | + intriParams.dValue = layoutSrc.shape(1); | ||
| 683 | + intriParams.srcNdMatrixStride = 0; | ||
| 684 | + intriParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 685 | + intriParams.dstNzMatrixStride = 0; | ||
| 686 | + | ||
| 687 | + if (layoutSrc.stride(0) < STRIDE_LIMIT) { | ||
| 688 | + intriParams.nValue = layoutSrc.shape(0); | ||
| 689 | + intriParams.srcDValue = layoutSrc.stride(0); | ||
| 690 | + intriParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 691 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 692 | + } else { | ||
| 693 | + intriParams.nValue = 1; | ||
| 694 | + intriParams.srcDValue = 0; | ||
| 695 | + intriParams.dstNzNStride = 0; | ||
| 696 | + for (uint32_t i = 0; i < layoutSrc.shape(0); i++) { | ||
| 697 | + AscendC::DataCopy(dstTensor[i * ELE_NUM_PER_C0], srcTensor[i * layoutSrc.stride(0)], intriParams); | ||
| 698 | + } | ||
| 699 | + } | ||
| 700 | + } | ||
| 701 | +}; | ||
| 702 | +///////////////////////////////// | ||
| 703 | + | ||
| 704 | +/// Partial specialization for AtlasA2, RowMajor in and zN out. | ||
| 705 | +template <class Element> | ||
| 706 | +struct CopyGmToL1<Arch::AtlasA2, Gemm::GemmType<Element, layout::RowMajor>> { | ||
| 707 | + using LayoutDst = layout::zN; | ||
| 708 | + using LayoutSrc = layout::RowMajor; | ||
| 709 | + | ||
| 710 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 711 | + | ||
| 712 | + // Mehtods | ||
| 713 | + | ||
| 714 | + __aicore__ inline | ||
| 715 | + CopyGmToL1() {}; | ||
| 716 | + | ||
| 717 | + __aicore__ inline | ||
| 718 | + void operator()( | ||
| 719 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 720 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 721 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 722 | + { | ||
| 723 | + AscendC::Nd2NzParams intriParams; | ||
| 724 | + | ||
| 725 | + intriParams.ndNum = 1; | ||
| 726 | + intriParams.dValue = layoutSrc.shape(1); | ||
| 727 | + intriParams.srcNdMatrixStride = 0; | ||
| 728 | + intriParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 729 | + intriParams.dstNzMatrixStride = 0; | ||
| 730 | + | ||
| 731 | + if (layoutSrc.stride(0) < STRIDE_LIMIT) { | ||
| 732 | + intriParams.nValue = layoutSrc.shape(0); | ||
| 733 | + intriParams.srcDValue = layoutSrc.stride(0); | ||
| 734 | + intriParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 735 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 736 | + } else { | ||
| 737 | + intriParams.nValue = 1; | ||
| 738 | + intriParams.srcDValue = 0; | ||
| 739 | + intriParams.dstNzNStride = 0; | ||
| 740 | + for (uint32_t i = 0; i < layoutSrc.shape(0); i++) { | ||
| 741 | + AscendC::DataCopy(dstTensor[i * ELE_NUM_PER_C0], srcTensor[i * layoutSrc.stride(0)], intriParams); | ||
| 742 | + } | ||
| 743 | + } | ||
| 744 | + } | ||
| 745 | + | ||
| 746 | + // layoutSrc must be the layout of one of the src matrices | ||
| 747 | + __aicore__ inline | ||
| 748 | + void operator()( | ||
| 749 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 750 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 751 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc, | ||
| 752 | + uint32_t ndNum, uint32_t srcNdMatrixStride, | ||
| 753 | + uint32_t dstNzNStride, uint32_t dstNzMatrixStride, | ||
| 754 | + uint32_t dstNzC0Stride) | ||
| 755 | + { | ||
| 756 | + AscendC::Nd2NzParams intriParams; | ||
| 757 | + | ||
| 758 | + intriParams.nValue = layoutSrc.shape(0); | ||
| 759 | + intriParams.dValue = layoutSrc.shape(1); | ||
| 760 | + intriParams.srcDValue = layoutSrc.stride(0); | ||
| 761 | + intriParams.dstNzNStride = dstNzNStride; | ||
| 762 | + intriParams.dstNzC0Stride = dstNzC0Stride; | ||
| 763 | + if (srcNdMatrixStride < STRIDE_LIMIT) { | ||
| 764 | + intriParams.ndNum = ndNum; | ||
| 765 | + intriParams.srcNdMatrixStride = srcNdMatrixStride; | ||
| 766 | + intriParams.dstNzMatrixStride = dstNzMatrixStride; | ||
| 767 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 768 | + } else { | ||
| 769 | + intriParams.ndNum = 1; | ||
| 770 | + intriParams.srcNdMatrixStride = 0; | ||
| 771 | + intriParams.dstNzMatrixStride = 0; | ||
| 772 | + for (uint32_t i = 0; i < ndNum; i++) { | ||
| 773 | + AscendC::DataCopy(dstTensor[i * ELE_NUM_PER_C0], srcTensor[i * srcNdMatrixStride], intriParams); | ||
| 774 | + } | ||
| 775 | + } | ||
| 776 | + } | ||
| 777 | +}; | ||
| 778 | + | ||
| 779 | +/// Partial specialization for AtlasA2, ColumnMajor in and nZ out. | ||
| 780 | +template < | ||
| 781 | + class Element | ||
| 782 | +> | ||
| 783 | +struct CopyGmToL1<Arch::AtlasA2, Gemm::GemmType<Element, layout::ColumnMajor>> { | ||
| 784 | + using LayoutDst = layout::nZ; | ||
| 785 | + using LayoutSrc = layout::ColumnMajor; | ||
| 786 | + | ||
| 787 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 788 | + | ||
| 789 | + // Mehtods | ||
| 790 | + | ||
| 791 | + __aicore__ inline | ||
| 792 | + CopyGmToL1() {}; | ||
| 793 | + | ||
| 794 | + __aicore__ inline | ||
| 795 | + void operator()( | ||
| 796 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 797 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 798 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 799 | + { | ||
| 800 | + AscendC::Nd2NzParams intriParams; | ||
| 801 | + | ||
| 802 | + intriParams.ndNum = 1; | ||
| 803 | + intriParams.dValue = layoutSrc.shape(0); | ||
| 804 | + intriParams.srcNdMatrixStride = 0; | ||
| 805 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 806 | + intriParams.dstNzMatrixStride = 0; | ||
| 807 | + | ||
| 808 | + if (layoutSrc.stride(1) < STRIDE_LIMIT) { | ||
| 809 | + intriParams.nValue = layoutSrc.shape(1); | ||
| 810 | + intriParams.srcDValue = layoutSrc.stride(1); | ||
| 811 | + intriParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 812 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 813 | + } else { | ||
| 814 | + intriParams.nValue = 1; | ||
| 815 | + intriParams.srcDValue = 0; | ||
| 816 | + intriParams.dstNzNStride = 0; | ||
| 817 | + for (uint32_t i = 0; i < layoutSrc.shape(1); i++) { | ||
| 818 | + AscendC::DataCopy(dstTensor[i * ELE_NUM_PER_C0], srcTensor[i * layoutSrc.stride(1)], intriParams); | ||
| 819 | + } | ||
| 820 | + } | ||
| 821 | + } | ||
| 822 | +}; | ||
| 823 | + | ||
| 824 | +/// Partial specialization for zN in and zN out. | ||
| 825 | +template < | ||
| 826 | + class ArchTag, | ||
| 827 | + class Element | ||
| 828 | +> | ||
| 829 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::zN>> { | ||
| 830 | + using LayoutDst = layout::zN; | ||
| 831 | + using LayoutSrc = layout::zN; | ||
| 832 | + | ||
| 833 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 834 | + | ||
| 835 | + // Mehtods | ||
| 836 | + | ||
| 837 | + __aicore__ inline | ||
| 838 | + CopyGmToL1() {}; | ||
| 839 | + | ||
| 840 | + __aicore__ inline | ||
| 841 | + void operator()( | ||
| 842 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 843 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 844 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 845 | + { | ||
| 846 | + uint32_t blockCount = CeilDiv<ELE_NUM_PER_C0>(layoutSrc.orgShape(1)); | ||
| 847 | + uint32_t blockLen = RoundUp<C0_NUM_PER_FRACTAL>(layoutSrc.orgShape(0)); | ||
| 848 | + | ||
| 849 | + AscendC::DataCopyParams repeatParams; | ||
| 850 | + | ||
| 851 | + if (layoutSrc.stride(3) / ELE_NUM_PER_C0 < STRIDE_LIMIT) { | ||
| 852 | + repeatParams.blockCount = blockCount; | ||
| 853 | + repeatParams.blockLen = blockLen; | ||
| 854 | + repeatParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_C0 - blockLen; | ||
| 855 | + repeatParams.dstStride = layoutDst.stride(3) / ELE_NUM_PER_C0 - blockLen; | ||
| 856 | + AscendC::DataCopy(dstTensor, srcTensor, repeatParams); | ||
| 857 | + } else { | ||
| 858 | + repeatParams.blockCount = 1; | ||
| 859 | + repeatParams.blockLen = blockLen; | ||
| 860 | + repeatParams.srcStride = 0; | ||
| 861 | + repeatParams.dstStride = 0; | ||
| 862 | + for (uint32_t i = 0; i < blockCount; i++) { | ||
| 863 | + uint64_t dstOffset = i * layoutDst.stride(3); | ||
| 864 | + uint64_t srcOffset = i * layoutSrc.stride(3); | ||
| 865 | + AscendC::DataCopy(dstTensor[dstOffset], srcTensor[srcOffset], repeatParams); | ||
| 866 | + } | ||
| 867 | + } | ||
| 868 | + } | ||
| 869 | +}; | ||
| 870 | + | ||
| 871 | +/// Partial specialization for nZ in and nZ out. | ||
| 872 | +template < | ||
| 873 | + class ArchTag, | ||
| 874 | + class Element | ||
| 875 | +> | ||
| 876 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::nZ>> { | ||
| 877 | + using LayoutDst = layout::nZ; | ||
| 878 | + using LayoutSrc = layout::nZ; | ||
| 879 | + | ||
| 880 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 881 | + | ||
| 882 | + // Mehtods | ||
| 883 | + | ||
| 884 | + __aicore__ inline | ||
| 885 | + CopyGmToL1() {}; | ||
| 886 | + | ||
| 887 | + __aicore__ inline | ||
| 888 | + void operator()( | ||
| 889 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 890 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 891 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 892 | + { | ||
| 893 | + uint32_t blockCount = CeilDiv<ELE_NUM_PER_C0>(layoutSrc.orgShape(0)); | ||
| 894 | + uint32_t blockLen = RoundUp<C0_NUM_PER_FRACTAL>(layoutSrc.orgShape(1)); | ||
| 895 | + | ||
| 896 | + AscendC::DataCopyParams repeatParams; | ||
| 897 | + | ||
| 898 | + if (layoutSrc.stride(1) / ELE_NUM_PER_C0 < STRIDE_LIMIT) { | ||
| 899 | + repeatParams.blockCount = blockCount; | ||
| 900 | + repeatParams.blockLen = blockLen; | ||
| 901 | + repeatParams.srcStride = layoutSrc.stride(1) / ELE_NUM_PER_C0 - blockLen; | ||
| 902 | + repeatParams.dstStride = layoutDst.stride(1) / ELE_NUM_PER_C0 - blockLen; | ||
| 903 | + AscendC::DataCopy(dstTensor, srcTensor, repeatParams); | ||
| 904 | + } else { | ||
| 905 | + repeatParams.blockCount = 1; | ||
| 906 | + repeatParams.blockLen = blockLen; | ||
| 907 | + repeatParams.srcStride = 0; | ||
| 908 | + repeatParams.dstStride = 0; | ||
| 909 | + for (uint32_t i = 0; i < blockCount; i++) { | ||
| 910 | + uint64_t dstOffset = i * layoutDst.stride(1); | ||
| 911 | + uint64_t srcOffset = i * layoutSrc.stride(1); | ||
| 912 | + AscendC::DataCopy(dstTensor[dstOffset], srcTensor[srcOffset], repeatParams); | ||
| 913 | + } | ||
| 914 | + } | ||
| 915 | + } | ||
| 916 | +}; | ||
| 917 | + | ||
| 918 | +/// Partial specialization for AtlasA2, PaddingRowMajor in and zN out. | ||
| 919 | +template <class Element> | ||
| 920 | +struct CopyGmToL1<Arch::AtlasA2, Gemm::GemmType<Element, layout::PaddingRowMajor>> { | ||
| 921 | + using LayoutDst = layout::zN; | ||
| 922 | + using LayoutSrc = layout::PaddingRowMajor; | ||
| 923 | + | ||
| 924 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 925 | + | ||
| 926 | + // Mehtods | ||
| 927 | + | ||
| 928 | + __aicore__ inline | ||
| 929 | + CopyGmToL1() {}; | ||
| 930 | + | ||
| 931 | + __aicore__ inline | ||
| 932 | + void operator()( | ||
| 933 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 934 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 935 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 936 | + { | ||
| 937 | + AscendC::Nd2NzParams intriParams; | ||
| 938 | + | ||
| 939 | + intriParams.ndNum = 1; | ||
| 940 | + intriParams.dValue = layoutSrc.orgShape(1); | ||
| 941 | + intriParams.srcNdMatrixStride = 0; | ||
| 942 | + intriParams.dstNzC0Stride = layoutDst.stride(3) / ELE_NUM_PER_C0; | ||
| 943 | + intriParams.dstNzMatrixStride = 0; | ||
| 944 | + | ||
| 945 | + intriParams.nValue = layoutSrc.orgShape(0); | ||
| 946 | + intriParams.srcDValue = layoutSrc.stride(0); | ||
| 947 | + intriParams.dstNzNStride = layoutDst.stride(0) / ELE_NUM_PER_C0; | ||
| 948 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 949 | + } | ||
| 950 | +}; | ||
| 951 | + | ||
| 952 | +/// Partial specialization for AtlasA2, ColumnMajor in and nZ out. | ||
| 953 | +template < | ||
| 954 | + class Element | ||
| 955 | +> | ||
| 956 | +struct CopyGmToL1<Arch::AtlasA2, Gemm::GemmType<Element, layout::PaddingColumnMajor>> { | ||
| 957 | + using LayoutDst = layout::nZ; | ||
| 958 | + using LayoutSrc = layout::PaddingColumnMajor; | ||
| 959 | + | ||
| 960 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 961 | + | ||
| 962 | + // Mehtods | ||
| 963 | + | ||
| 964 | + __aicore__ inline | ||
| 965 | + CopyGmToL1() {}; | ||
| 966 | + | ||
| 967 | + __aicore__ inline | ||
| 968 | + void operator()( | ||
| 969 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 970 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 971 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 972 | + { | ||
| 973 | + AscendC::Nd2NzParams intriParams; | ||
| 974 | + | ||
| 975 | + intriParams.ndNum = 1; | ||
| 976 | + intriParams.dValue = layoutSrc.orgShape(0); | ||
| 977 | + intriParams.srcNdMatrixStride = 0; | ||
| 978 | + intriParams.dstNzC0Stride = layoutDst.stride(1) / ELE_NUM_PER_C0; | ||
| 979 | + intriParams.dstNzMatrixStride = 0; | ||
| 980 | + | ||
| 981 | + intriParams.nValue = layoutSrc.orgShape(1); | ||
| 982 | + intriParams.srcDValue = layoutSrc.stride(2); | ||
| 983 | + intriParams.dstNzNStride = layoutDst.stride(2) / ELE_NUM_PER_C0; | ||
| 984 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 985 | + } | ||
| 986 | +}; | ||
| 987 | + | ||
| 988 | +/// Partial specialization for AtlasA2, RowMajor in and RowMajor out. | ||
| 989 | +template <class Element> | ||
| 990 | +struct CopyGmToL1<Arch::AtlasA2, Gemm::GemmType<Element, layout::RowMajor>, | ||
| 991 | + Gemm::GemmType<Element, layout::RowMajor, AscendC::TPosition::A1>> { | ||
| 992 | + using LayoutDst = layout::RowMajor; | ||
| 993 | + using LayoutSrc = layout::RowMajor; | ||
| 994 | + | ||
| 995 | + static constexpr uint32_t ELE_NUM_PER_BLK = BYTE_PER_BLK / sizeof(Element); | ||
| 996 | + static constexpr uint32_t BLOCK_LEN_LIMIT = 65536; | ||
| 997 | + static constexpr uint32_t MAX_REPEAT = 4095; | ||
| 998 | + | ||
| 999 | + // Mehtods | ||
| 1000 | + | ||
| 1001 | + __aicore__ inline | ||
| 1002 | + CopyGmToL1() {}; | ||
| 1003 | + | ||
| 1004 | + __aicore__ inline | ||
| 1005 | + void operator()( | ||
| 1006 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 1007 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 1008 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 1009 | + { | ||
| 1010 | + uint32_t rows = layoutSrc.shape(0); | ||
| 1011 | + uint32_t cols = layoutSrc.shape(1); | ||
| 1012 | + uint32_t srcStride = (layoutSrc.stride(0) - layoutSrc.shape(1)) / ELE_NUM_PER_BLK; | ||
| 1013 | + uint32_t dstStride = (layoutDst.stride(0) - layoutDst.shape(1)) / ELE_NUM_PER_BLK; | ||
| 1014 | + | ||
| 1015 | + if ((layoutSrc.shape(1) == layoutSrc.stride(0)) && (layoutDst.shape(1) == layoutDst.stride(0))) { | ||
| 1016 | + DataCopy(dstTensor, srcTensor, rows * cols); | ||
| 1017 | + } else if (srcStride < STRIDE_LIMIT && dstStride < STRIDE_LIMIT && (cols / ELE_NUM_PER_BLK) < BLOCK_LEN_LIMIT) { | ||
| 1018 | + uint32_t rLoops = CeilDiv(rows, MAX_REPEAT); | ||
| 1019 | + for (uint32_t i = 0; i < rLoops; ++i) { | ||
| 1020 | + uint32_t rActual = (i < rLoops - 1) ? MAX_REPEAT : rows - i * MAX_REPEAT; | ||
| 1021 | + AscendC::DataCopyParams dataCopyParams( | ||
| 1022 | + rActual, cols / ELE_NUM_PER_BLK, srcStride, dstStride | ||
| 1023 | + ); | ||
| 1024 | + DataCopy(dstTensor[i * MAX_REPEAT * layoutDst.stride(0)], | ||
| 1025 | + srcTensor[i * MAX_REPEAT * layoutSrc.stride(0)], dataCopyParams); | ||
| 1026 | + } | ||
| 1027 | + } else { | ||
| 1028 | + for (uint32_t i = 0; i < rows; ++i) { | ||
| 1029 | + DataCopy(dstTensor[i * layoutDst.stride(0)], srcTensor[i * layoutSrc.stride(0)], cols); | ||
| 1030 | + } | ||
| 1031 | + } | ||
| 1032 | + } | ||
| 1033 | +}; | ||
| 1034 | + | ||
| 1035 | +template <class ArchTag, class Element> | ||
| 1036 | +struct CopyGmToL1<ArchTag, Gemm::GemmType<Element, layout::VectorLayout, AscendC::TPosition::GM>, | ||
| 1037 | + Gemm::GemmType<Element, layout::VectorLayout, AscendC::TPosition::A1>> { | ||
| 1038 | + using LayoutDst = layout::VectorLayout; | ||
| 1039 | + using LayoutSrc = layout::VectorLayout; | ||
| 1040 | + | ||
| 1041 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 1042 | + | ||
| 1043 | + // Mehtods | ||
| 1044 | + | ||
| 1045 | + __aicore__ inline | ||
| 1046 | + CopyGmToL1() {}; | ||
| 1047 | + | ||
| 1048 | + __aicore__ inline | ||
| 1049 | + void operator()( | ||
| 1050 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 1051 | + AscendC::GlobalTensor<Element> const &srcTensor, | ||
| 1052 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 1053 | + { | ||
| 1054 | + AscendC::DataCopyParams intriParams; | ||
| 1055 | + intriParams.blockCount = 1; | ||
| 1056 | + intriParams.blockLen = layoutDst.shape(0) / ELE_NUM_PER_C0; | ||
| 1057 | + intriParams.srcStride = 0; | ||
| 1058 | + intriParams.dstStride = 0; | ||
| 1059 | + AscendC::DataCopy(dstTensor, srcTensor, intriParams); | ||
| 1060 | + } | ||
| 1061 | +}; | ||
| 1062 | + | ||
| 1063 | + | ||
| 1064 | +///////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 1065 | + | ||
| 1066 | +} // namespace NpuArch::Gemm::Tile | ||
| 1067 | + | ||
| 1068 | + | ||
| @@ -0,0 +1,221 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::Gemm::Tile { | ||
| 20 | + | ||
| 21 | +/// Partial specialization for CopyGmToL1, AtlasA5, RowMajor in and zN out. | ||
| 22 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 23 | +struct TileCopyTla< | ||
| 24 | + Arch::AtlasA5, | ||
| 25 | + tla::Tensor<AscendC::GlobalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::GM>, | ||
| 26 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::A1>, | ||
| 27 | + std::enable_if_t<tla::detail::isRowMajor<LayoutSrc>::value && tla::detail::iszN<ElementDst, LayoutDst>::value>> { | ||
| 28 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 29 | + | ||
| 30 | + // Methods | ||
| 31 | + | ||
| 32 | + __aicore__ inline | ||
| 33 | + TileCopyTla() {}; | ||
| 34 | + | ||
| 35 | + template <class TensorDst, class TensorSrc> | ||
| 36 | + __aicore__ inline void operator()( | ||
| 37 | + TensorDst const &dstTensor, | ||
| 38 | + TensorSrc const &srcTensor, | ||
| 39 | + uint32_t ndNum = 1, | ||
| 40 | + uint32_t srcNdMatrixStride = 0, | ||
| 41 | + uint32_t dstNzMatrixStride = 0 | ||
| 42 | + ) | ||
| 43 | + { | ||
| 44 | + static_assert( | ||
| 45 | + tla::detail::isRowMajor<typename TensorSrc::Layout>::value | ||
| 46 | + && tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 47 | + && TensorSrc::position == AscendC::TPosition::GM && TensorDst::position == AscendC::TPosition::A1, | ||
| 48 | + "The input parameters do not match. TensorSrc must be GM and RowMajor, while TensorDst must be L1 and zN" | ||
| 49 | + ); | ||
| 50 | + | ||
| 51 | + const uint32_t nValue = tla::get<0>(srcTensor.shape()); | ||
| 52 | + const uint32_t dValue = tla::get<1>(srcTensor.shape()); | ||
| 53 | + const uint32_t srcDValue = tla::get<0>(srcTensor.stride()); | ||
| 54 | + const uint32_t dstInnerStrideRow = tla::get<0, 0>(dstTensor.stride()); | ||
| 55 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 56 | + | ||
| 57 | + AscendC::Nd2NzParams intriParams; | ||
| 58 | + | ||
| 59 | + intriParams.ndNum = ndNum; | ||
| 60 | + intriParams.nValue = nValue; | ||
| 61 | + intriParams.dValue = dValue; | ||
| 62 | + intriParams.srcNdMatrixStride = srcNdMatrixStride; | ||
| 63 | + intriParams.srcDValue = srcDValue; | ||
| 64 | + intriParams.dstNzC0Stride = dstOuterStrideCol / ELE_NUM_PER_C0; | ||
| 65 | + intriParams.dstNzNStride = dstInnerStrideRow / ELE_NUM_PER_C0; | ||
| 66 | + intriParams.dstNzMatrixStride = dstNzMatrixStride; | ||
| 67 | + | ||
| 68 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 69 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 70 | + | ||
| 71 | + AscendC::DataCopy(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 72 | + } | ||
| 73 | +}; | ||
| 74 | + | ||
| 75 | +/// Partial specialization for CopyGmToL1, AtlasA5, zN in and zN out. | ||
| 76 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 77 | +struct TileCopyTla< | ||
| 78 | + Arch::AtlasA5, | ||
| 79 | + tla::Tensor<AscendC::GlobalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::GM>, | ||
| 80 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::A1>, | ||
| 81 | + std::enable_if_t<tla::detail::iszN<ElementSrc, LayoutSrc>::value && tla::detail::iszN<ElementDst, LayoutDst>::value>> { | ||
| 82 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 83 | + | ||
| 84 | + // Methods | ||
| 85 | + | ||
| 86 | + __aicore__ inline | ||
| 87 | + TileCopyTla() {}; | ||
| 88 | + | ||
| 89 | + template <class TensorDst, class TensorSrc> | ||
| 90 | + __aicore__ inline void operator()( | ||
| 91 | + TensorDst const &dstTensor, | ||
| 92 | + TensorSrc const &srcTensor | ||
| 93 | + ) | ||
| 94 | + { | ||
| 95 | + static_assert( | ||
| 96 | + tla::detail::iszN<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 97 | + && tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 98 | + && TensorSrc::position == AscendC::TPosition::GM && TensorDst::position == AscendC::TPosition::A1, | ||
| 99 | + "The input parameters do not match. TensorSrc must be GM and zN, while TensorDst must be L1 and zN" | ||
| 100 | + ); | ||
| 101 | + | ||
| 102 | + const uint32_t blockCount = tla::get<1, 1>(srcTensor.shape()); | ||
| 103 | + const uint32_t blockLen = tla::get<0, 0>(srcTensor.shape()) * tla::get<0, 1>(srcTensor.shape()); | ||
| 104 | + | ||
| 105 | + AscendC::DataCopyParams repeatParams; | ||
| 106 | + | ||
| 107 | + repeatParams.blockCount = blockCount; | ||
| 108 | + repeatParams.blockLen = blockLen; | ||
| 109 | + repeatParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / ELE_NUM_PER_C0 - blockLen; | ||
| 110 | + repeatParams.dstStride = tla::get<1, 1>(dstTensor.stride()) / ELE_NUM_PER_C0 - blockLen; | ||
| 111 | + | ||
| 112 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 113 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 114 | + | ||
| 115 | + AscendC::DataCopy(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], repeatParams); | ||
| 116 | + } | ||
| 117 | +}; | ||
| 118 | + | ||
| 119 | +/// Partial specialization for CopyGmToL1, AtlasA5, ColumnMajor in and nZ out. | ||
| 120 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 121 | +struct TileCopyTla< | ||
| 122 | + Arch::AtlasA5, | ||
| 123 | + tla::Tensor<AscendC::GlobalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::GM>, | ||
| 124 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::A1>, | ||
| 125 | + std::enable_if_t<tla::detail::isColumnMajor<LayoutSrc>::value && tla::detail::isnZ<ElementDst, LayoutDst>::value>> { | ||
| 126 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 127 | + | ||
| 128 | + // Methods | ||
| 129 | + | ||
| 130 | + __aicore__ inline | ||
| 131 | + TileCopyTla() {}; | ||
| 132 | + | ||
| 133 | + template <class TensorDst, class TensorSrc> | ||
| 134 | + __aicore__ inline void operator()( | ||
| 135 | + TensorDst const &dstTensor, | ||
| 136 | + TensorSrc const &srcTensor, | ||
| 137 | + uint32_t ndNum = 1, | ||
| 138 | + uint32_t srcNdMatrixStride = 0, | ||
| 139 | + uint32_t dstNzMatrixStride = 0 | ||
| 140 | + ) | ||
| 141 | + { | ||
| 142 | + static_assert( | ||
| 143 | + tla::detail::isColumnMajor<typename TensorSrc::Layout>::value | ||
| 144 | + && tla::detail::isnZ<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 145 | + && TensorSrc::position == AscendC::TPosition::GM && TensorDst::position == AscendC::TPosition::A1, | ||
| 146 | + "The input parameters do not match. TensorSrc must be GM and ColumnMajor, " | ||
| 147 | + "while TensorDst must be L1 and nZ" | ||
| 148 | + ); | ||
| 149 | + | ||
| 150 | + const uint32_t nValue = tla::get<1>(srcTensor.shape()); | ||
| 151 | + const uint32_t dValue = tla::get<0>(srcTensor.shape()); | ||
| 152 | + const uint32_t srcDValue = tla::get<1>(srcTensor.stride()); | ||
| 153 | + const uint32_t dstInnerStrideCol = tla::get<1, 0>(dstTensor.stride()); | ||
| 154 | + const uint32_t dstOuterStrideRow = tla::get<0, 1>(dstTensor.stride()); | ||
| 155 | + | ||
| 156 | + AscendC::Nd2NzParams intriParams; | ||
| 157 | + | ||
| 158 | + intriParams.ndNum = ndNum; | ||
| 159 | + intriParams.nValue = nValue; | ||
| 160 | + intriParams.dValue = dValue; | ||
| 161 | + intriParams.srcNdMatrixStride = srcNdMatrixStride; | ||
| 162 | + intriParams.srcDValue = srcDValue; | ||
| 163 | + intriParams.dstNzC0Stride = dstOuterStrideRow / ELE_NUM_PER_C0; | ||
| 164 | + intriParams.dstNzNStride = dstInnerStrideCol / ELE_NUM_PER_C0; | ||
| 165 | + intriParams.dstNzMatrixStride = dstNzMatrixStride; | ||
| 166 | + | ||
| 167 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 168 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 169 | + | ||
| 170 | + AscendC::DataCopy(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 171 | + } | ||
| 172 | +}; | ||
| 173 | + | ||
| 174 | +/// Partial specialization for CopyGmToL1, AtlasA5, nZ in and nZ out. | ||
| 175 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 176 | +struct TileCopyTla< | ||
| 177 | + Arch::AtlasA5, | ||
| 178 | + tla::Tensor<AscendC::GlobalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::GM>, | ||
| 179 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::A1>, | ||
| 180 | + std::enable_if_t<tla::detail::isnZ<ElementSrc, LayoutSrc>::value && tla::detail::isnZ<ElementDst, LayoutDst>::value>> { | ||
| 181 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 182 | + | ||
| 183 | + // Methods | ||
| 184 | + | ||
| 185 | + __aicore__ inline | ||
| 186 | + TileCopyTla() {}; | ||
| 187 | + | ||
| 188 | + template <class TensorDst, class TensorSrc> | ||
| 189 | + __aicore__ inline void operator()( | ||
| 190 | + TensorDst const &dstTensor, | ||
| 191 | + TensorSrc const &srcTensor | ||
| 192 | + ) | ||
| 193 | + { | ||
| 194 | + static_assert( | ||
| 195 | + tla::detail::isnZ<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 196 | + && tla::detail::isnZ<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 197 | + && TensorSrc::position == AscendC::TPosition::GM && TensorDst::position == AscendC::TPosition::A1, | ||
| 198 | + "The input parameters do not match. TensorSrc must be GM and nZ, " | ||
| 199 | + "while TensorDst must be L1 and nZ" | ||
| 200 | + ); | ||
| 201 | + | ||
| 202 | + const uint32_t blockCount = tla::get<0, 1>(srcTensor.shape()); | ||
| 203 | + const uint32_t blockLen = tla::get<1, 0>(srcTensor.shape()) * tla::get<1, 1>(srcTensor.shape()); | ||
| 204 | + | ||
| 205 | + AscendC::DataCopyParams repeatParams; | ||
| 206 | + | ||
| 207 | + repeatParams.blockCount = blockCount; | ||
| 208 | + repeatParams.blockLen = blockLen; | ||
| 209 | + repeatParams.srcStride = tla::get<0, 1>(srcTensor.stride()) / ELE_NUM_PER_C0 - blockLen; | ||
| 210 | + repeatParams.dstStride = tla::get<0, 1>(dstTensor.stride()) / ELE_NUM_PER_C0 - blockLen; | ||
| 211 | + | ||
| 212 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 213 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 214 | + | ||
| 215 | + AscendC::DataCopy(dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], repeatParams); | ||
| 216 | + } | ||
| 217 | +}; | ||
| 218 | + | ||
| 219 | +} // namespace NpuArch::Gemm::Tile | ||
| 220 | + | ||
| 221 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/gemm/tile_common/copy_gm_to_ub.hpp+22-0
| @@ -0,0 +1,22 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace NpuArch::Gemm::Tile { | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +} // NpuArch::Gemm::Tile | ||
| 21 | + | ||
| 22 | + | ||
| @@ -0,0 +1,283 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::Gemm::Tile { | ||
| 20 | + | ||
| 21 | +enum class ScaleGranularity { | ||
| 22 | + UNDEFINED = -1, | ||
| 23 | + NO_QUANT = 0, | ||
| 24 | + PER_TENSOR, | ||
| 25 | + PER_CHANNEL, | ||
| 26 | + PER_GROUP | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +template < | ||
| 30 | + class ArchTag, | ||
| 31 | + class ElementSrc, | ||
| 32 | + class ElementDst, | ||
| 33 | + ScaleGranularity DEQUANT_GRANULARITY = ScaleGranularity::NO_QUANT | ||
| 34 | +> | ||
| 35 | +struct CopyL0CToDstQuantMode { | ||
| 36 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy l0c to gm, can not find the specialization."); | ||
| 37 | +}; | ||
| 38 | + | ||
| 39 | +// CopyL0CToGm fp32 to fp32 | ||
| 40 | +template <class ArchTag> | ||
| 41 | +struct CopyL0CToDstQuantMode< | ||
| 42 | + ArchTag, | ||
| 43 | + float, float, | ||
| 44 | + ScaleGranularity::NO_QUANT | ||
| 45 | +> { | ||
| 46 | + static constexpr auto VALUE = QuantMode_t::NoQuant; | ||
| 47 | +}; | ||
| 48 | + | ||
| 49 | +// CopyL0CToGm fp32 to fp32 | ||
| 50 | + | ||
| 51 | +template <> | ||
| 52 | +struct CopyL0CToDstQuantMode< | ||
| 53 | + NpuArch::Arch::AtlasA5, | ||
| 54 | + float, float, | ||
| 55 | + ScaleGranularity::PER_CHANNEL | ||
| 56 | +> { | ||
| 57 | + static constexpr auto VALUE = QuantMode_t::VQF322F32_PRE; | ||
| 58 | +}; | ||
| 59 | + | ||
| 60 | + | ||
| 61 | + | ||
| 62 | +// CopyL0CToGm cast fp32 to fp16 | ||
| 63 | +template <class ArchTag> | ||
| 64 | +struct CopyL0CToDstQuantMode< | ||
| 65 | + ArchTag, | ||
| 66 | + float, half, | ||
| 67 | + ScaleGranularity::NO_QUANT | ||
| 68 | +> { | ||
| 69 | + static constexpr auto VALUE = QuantMode_t::F322F16; | ||
| 70 | +}; | ||
| 71 | + | ||
| 72 | +template <class ArchTag> | ||
| 73 | +struct CopyL0CToDstQuantMode< | ||
| 74 | + ArchTag, | ||
| 75 | + float, half, | ||
| 76 | + ScaleGranularity::PER_TENSOR | ||
| 77 | +> { | ||
| 78 | + static constexpr auto VALUE = QuantMode_t::QF322F16_PRE; | ||
| 79 | +}; | ||
| 80 | + | ||
| 81 | +template <class ArchTag> | ||
| 82 | +struct CopyL0CToDstQuantMode< | ||
| 83 | + ArchTag, | ||
| 84 | + float, half, | ||
| 85 | + ScaleGranularity::PER_CHANNEL | ||
| 86 | +> { | ||
| 87 | + static constexpr auto VALUE = QuantMode_t::VQF322F16_PRE; | ||
| 88 | +}; | ||
| 89 | + | ||
| 90 | +// CopyL0CToGm cast fp32 to bf16 | ||
| 91 | +template <class ArchTag> | ||
| 92 | +struct CopyL0CToDstQuantMode< | ||
| 93 | + ArchTag, | ||
| 94 | + float, bfloat16_t, | ||
| 95 | + ScaleGranularity::NO_QUANT | ||
| 96 | +> { | ||
| 97 | + static constexpr auto VALUE = QuantMode_t::F322BF16; | ||
| 98 | +}; | ||
| 99 | + | ||
| 100 | +template <class ArchTag> | ||
| 101 | +struct CopyL0CToDstQuantMode< | ||
| 102 | + ArchTag, | ||
| 103 | + float, bfloat16_t, | ||
| 104 | + ScaleGranularity::PER_TENSOR | ||
| 105 | +> { | ||
| 106 | + static constexpr auto VALUE = QuantMode_t::QF322BF16_PRE; | ||
| 107 | +}; | ||
| 108 | + | ||
| 109 | +template <class ArchTag> | ||
| 110 | +struct CopyL0CToDstQuantMode< | ||
| 111 | + ArchTag, | ||
| 112 | + float, bfloat16_t, | ||
| 113 | + ScaleGranularity::PER_CHANNEL | ||
| 114 | +> { | ||
| 115 | + static constexpr auto VALUE = QuantMode_t::VQF322BF16_PRE; | ||
| 116 | +}; | ||
| 117 | + | ||
| 118 | +// CopyL0CToGm cast float to uint8/int8 | ||
| 119 | +template <class ArchTag> | ||
| 120 | +struct CopyL0CToDstQuantMode< | ||
| 121 | + ArchTag, | ||
| 122 | + float, uint8_t, | ||
| 123 | + ScaleGranularity::PER_TENSOR | ||
| 124 | +> { | ||
| 125 | + static constexpr auto VALUE = QuantMode_t::QF322B8_PRE; | ||
| 126 | +}; | ||
| 127 | + | ||
| 128 | +template <class ArchTag> | ||
| 129 | +struct CopyL0CToDstQuantMode< | ||
| 130 | + ArchTag, | ||
| 131 | + float, uint8_t, | ||
| 132 | + ScaleGranularity::PER_CHANNEL | ||
| 133 | +> { | ||
| 134 | + static constexpr auto VALUE = QuantMode_t::VQF322B8_PRE; | ||
| 135 | +}; | ||
| 136 | + | ||
| 137 | +template <class ArchTag> | ||
| 138 | +struct CopyL0CToDstQuantMode< | ||
| 139 | + ArchTag, | ||
| 140 | + float, int8_t, | ||
| 141 | + ScaleGranularity::PER_TENSOR | ||
| 142 | +> { | ||
| 143 | + static constexpr auto VALUE = QuantMode_t::QF322B8_PRE; | ||
| 144 | +}; | ||
| 145 | + | ||
| 146 | +template <class ArchTag> | ||
| 147 | +struct CopyL0CToDstQuantMode< | ||
| 148 | + ArchTag, | ||
| 149 | + float, int8_t, | ||
| 150 | + ScaleGranularity::PER_CHANNEL | ||
| 151 | +> { | ||
| 152 | + static constexpr auto VALUE = QuantMode_t::VQF322B8_PRE; | ||
| 153 | +}; | ||
| 154 | + | ||
| 155 | +// CopyL0CToGm output int32 | ||
| 156 | +template <class ArchTag> | ||
| 157 | +struct CopyL0CToDstQuantMode< | ||
| 158 | + ArchTag, | ||
| 159 | + int32_t, int32_t, | ||
| 160 | + ScaleGranularity::NO_QUANT | ||
| 161 | +> { | ||
| 162 | + static constexpr auto VALUE = QuantMode_t::NoQuant; | ||
| 163 | +}; | ||
| 164 | + | ||
| 165 | +// CopyL0CToGm cast int32_t to fp16 | ||
| 166 | +template <class ArchTag> | ||
| 167 | +struct CopyL0CToDstQuantMode< | ||
| 168 | + ArchTag, | ||
| 169 | + int32_t, half, | ||
| 170 | + ScaleGranularity::PER_TENSOR | ||
| 171 | +> { | ||
| 172 | + static constexpr auto VALUE = QuantMode_t::DEQF16; | ||
| 173 | +}; | ||
| 174 | + | ||
| 175 | +// CopyL0CToGm cast int32_t to fp16 | ||
| 176 | +template <class ArchTag> | ||
| 177 | +struct CopyL0CToDstQuantMode< | ||
| 178 | + ArchTag, | ||
| 179 | + int32_t, half, | ||
| 180 | + ScaleGranularity::NO_QUANT | ||
| 181 | +> { | ||
| 182 | + static constexpr auto VALUE = QuantMode_t::DEQF16; | ||
| 183 | +}; | ||
| 184 | + | ||
| 185 | +template <class ArchTag> | ||
| 186 | +struct CopyL0CToDstQuantMode< | ||
| 187 | + ArchTag, | ||
| 188 | + int32_t, half, | ||
| 189 | + ScaleGranularity::PER_CHANNEL | ||
| 190 | +> { | ||
| 191 | + static constexpr auto VALUE = QuantMode_t::VDEQF16; | ||
| 192 | +}; | ||
| 193 | + | ||
| 194 | +// CopyL0CToGm cast int32 to uint8/int8 | ||
| 195 | +template <class ArchTag> | ||
| 196 | +struct CopyL0CToDstQuantMode< | ||
| 197 | + ArchTag, | ||
| 198 | + int32_t, uint8_t, | ||
| 199 | + ScaleGranularity::PER_TENSOR | ||
| 200 | +> { | ||
| 201 | + static constexpr auto VALUE = QuantMode_t::REQ8; | ||
| 202 | +}; | ||
| 203 | + | ||
| 204 | +template <class ArchTag> | ||
| 205 | +struct CopyL0CToDstQuantMode< | ||
| 206 | + ArchTag, | ||
| 207 | + int32_t, uint8_t, | ||
| 208 | + ScaleGranularity::PER_CHANNEL | ||
| 209 | +> { | ||
| 210 | + static constexpr auto VALUE = QuantMode_t::VREQ8; | ||
| 211 | +}; | ||
| 212 | + | ||
| 213 | +template <class ArchTag> | ||
| 214 | +struct CopyL0CToDstQuantMode< | ||
| 215 | + ArchTag, | ||
| 216 | + int32_t, int8_t, | ||
| 217 | + ScaleGranularity::PER_TENSOR | ||
| 218 | +> { | ||
| 219 | + static constexpr auto VALUE = QuantMode_t::REQ8; | ||
| 220 | +}; | ||
| 221 | + | ||
| 222 | +template <class ArchTag> | ||
| 223 | +struct CopyL0CToDstQuantMode< | ||
| 224 | + ArchTag, | ||
| 225 | + int32_t, int8_t, | ||
| 226 | + ScaleGranularity::PER_CHANNEL | ||
| 227 | +> { | ||
| 228 | + static constexpr auto VALUE = QuantMode_t::VREQ8; | ||
| 229 | +}; | ||
| 230 | + | ||
| 231 | +template < | ||
| 232 | + class ArchTag, | ||
| 233 | + class ElementAccumulator, | ||
| 234 | + class GmType, | ||
| 235 | + ScaleGranularity DEQUANT_GRANULARITY = ScaleGranularity::NO_QUANT, | ||
| 236 | + bool ReluEnable = false | ||
| 237 | +> | ||
| 238 | +struct CopyL0CToGm { | ||
| 239 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy l0c to gm, can not find the specialization."); | ||
| 240 | +}; | ||
| 241 | + | ||
| 242 | +///////////////////////////////////////////CopyL0CToGmTla///////////////////////////////////////////////// | ||
| 243 | +// L0C copy mode | ||
| 244 | +struct CopyToGM {}; | ||
| 245 | +struct CopyToL1 {}; | ||
| 246 | + | ||
| 247 | +template < | ||
| 248 | + class ArchTag, | ||
| 249 | + class TensorSrc, | ||
| 250 | + class TensorDst, | ||
| 251 | + ScaleGranularity DEQUANT_GRANULARITY = ScaleGranularity::NO_QUANT, | ||
| 252 | + bool ReluEnable = false, | ||
| 253 | + class Enable = void | ||
| 254 | +> | ||
| 255 | +struct CopyL0CToGmTla { | ||
| 256 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy l0c to gm, can not find the specialization."); | ||
| 257 | +}; | ||
| 258 | + | ||
| 259 | +///////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 260 | + | ||
| 261 | +enum class CopyL0CToUBMode { | ||
| 262 | + NO_SPLIT = 0, | ||
| 263 | + SPLIT_M, | ||
| 264 | + SPLIT_N, | ||
| 265 | + RESERVED | ||
| 266 | +}; | ||
| 267 | + | ||
| 268 | +template < | ||
| 269 | + class ArchTag, | ||
| 270 | + class TensorSrc, | ||
| 271 | + class TensorDst, | ||
| 272 | + CopyL0CToUBMode CopyMode = CopyL0CToUBMode::NO_SPLIT, | ||
| 273 | + ScaleGranularity DEQUANT_GRANULARITY = ScaleGranularity::NO_QUANT, | ||
| 274 | + bool ReluEnable = false, | ||
| 275 | + class Enable = void | ||
| 276 | +> | ||
| 277 | +struct CopyL0CToUBTla { | ||
| 278 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy l0c to ub, can not find the specialization."); | ||
| 279 | +}; | ||
| 280 | + | ||
| 281 | +} // namespace NpuArch::Gemm::Tile | ||
| 282 | + | ||
| 283 | + | ||
| @@ -0,0 +1,106 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +namespace NpuArch::Gemm::Tile { | ||
| 19 | + | ||
| 20 | +template < | ||
| 21 | + class ElementAccumulator_, | ||
| 22 | + class ElementDst_, | ||
| 23 | + bool ReluEnable_ | ||
| 24 | +> | ||
| 25 | +struct CopyL0CToGm<NpuArch::Arch::AtlasA2, | ||
| 26 | + ElementAccumulator_, | ||
| 27 | + Gemm::GemmType<ElementDst_, layout::RowMajor>, | ||
| 28 | + ScaleGranularity::NO_QUANT, | ||
| 29 | + ReluEnable_> | ||
| 30 | +{ | ||
| 31 | + using ArchTag = NpuArch::Arch::AtlasA2; | ||
| 32 | + using ElementDst = ElementDst_; | ||
| 33 | + using ElementSrc = ElementAccumulator_; | ||
| 34 | + using LayoutSrc = NpuArch::layout::zN; | ||
| 35 | + using LayoutDst = NpuArch::layout::RowMajor; | ||
| 36 | + static constexpr auto quantPre = CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, | ||
| 37 | + ScaleGranularity::NO_QUANT>::VALUE; | ||
| 38 | + static constexpr auto reluEn = ReluEnable_; | ||
| 39 | + | ||
| 40 | + __aicore__ inline | ||
| 41 | + void operator()(AscendC::GlobalTensor<ElementDst> const &dst, AscendC::LocalTensor<ElementSrc> const &src, | ||
| 42 | + LayoutDst const &dstLayout, LayoutSrc const &srcLayout, uint8_t unitFlag = 0) | ||
| 43 | + { | ||
| 44 | + AscendC::FixpipeParamsV220 intriParams; | ||
| 45 | + | ||
| 46 | + // Fixpipe layout information | ||
| 47 | + intriParams.nSize = dstLayout.shape(1); | ||
| 48 | + intriParams.mSize = dstLayout.shape(0); | ||
| 49 | + intriParams.srcStride = srcLayout.stride(3) / srcLayout.stride(0); | ||
| 50 | + intriParams.dstStride = dstLayout.stride(0); | ||
| 51 | + | ||
| 52 | + // Fixpipe auxiliary arguments | ||
| 53 | + intriParams.quantPre = quantPre; | ||
| 54 | + intriParams.reluEn = reluEn; | ||
| 55 | + intriParams.unitFlag = unitFlag; | ||
| 56 | + | ||
| 57 | + // Call AscendC Fixpipe | ||
| 58 | + AscendC::Fixpipe<ElementDst, ElementSrc, AscendC::CFG_ROW_MAJOR>(dst, src, intriParams); | ||
| 59 | + } | ||
| 60 | +}; | ||
| 61 | + | ||
| 62 | +template < | ||
| 63 | + class ElementAccumulator_, | ||
| 64 | + class ElementDst_, | ||
| 65 | + bool ReluEnable_ | ||
| 66 | +> | ||
| 67 | +struct CopyL0CToGm<NpuArch::Arch::AtlasA2, | ||
| 68 | + ElementAccumulator_, | ||
| 69 | + Gemm::GemmType<ElementDst_, layout::zN>, | ||
| 70 | + ScaleGranularity::NO_QUANT, | ||
| 71 | + ReluEnable_> | ||
| 72 | +{ | ||
| 73 | + using ArchTag = NpuArch::Arch::AtlasA2; | ||
| 74 | + using ElementDst = ElementDst_; | ||
| 75 | + using ElementSrc = ElementAccumulator_; | ||
| 76 | + using LayoutSrc = NpuArch::layout::zN; | ||
| 77 | + using LayoutDst = NpuArch::layout::zN; | ||
| 78 | + static constexpr auto quantPre = CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, | ||
| 79 | + ScaleGranularity::NO_QUANT>::VALUE; | ||
| 80 | + static constexpr auto reluEn = ReluEnable_; | ||
| 81 | + | ||
| 82 | + __aicore__ inline | ||
| 83 | + void operator()(AscendC::GlobalTensor<ElementDst> const &dst, AscendC::LocalTensor<ElementSrc> const &src, | ||
| 84 | + LayoutDst const &dstLayout, LayoutSrc const &srcLayout, uint8_t unitFlag = 0) | ||
| 85 | + { | ||
| 86 | + AscendC::FixpipeParamsV220 intriParams; | ||
| 87 | + | ||
| 88 | + // Fixpipe layout information | ||
| 89 | + intriParams.nSize = dstLayout.shape(2) * dstLayout.shape(3); | ||
| 90 | + intriParams.mSize = dstLayout.shape(0) * dstLayout.shape(1); | ||
| 91 | + intriParams.srcStride = srcLayout.stride(3) / srcLayout.shape(2); | ||
| 92 | + intriParams.dstStride = dstLayout.stride(3) / (BYTE_PER_C0 / sizeof(ElementDst)); | ||
| 93 | + | ||
| 94 | + // Fixpipe auxiliary arguments | ||
| 95 | + intriParams.quantPre = quantPre; | ||
| 96 | + intriParams.reluEn = reluEn; | ||
| 97 | + intriParams.unitFlag = unitFlag; | ||
| 98 | + | ||
| 99 | + // Call AscendC Fixpipe | ||
| 100 | + AscendC::Fixpipe<ElementDst, ElementSrc, AscendC::CFG_NZ>(dst, src, intriParams); | ||
| 101 | + } | ||
| 102 | +}; | ||
| 103 | + | ||
| 104 | +} // namespace NpuArch::Gemm::Tile | ||
| 105 | + | ||
| 106 | + | ||
| @@ -0,0 +1,757 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +constexpr AscendC::FixpipeConfig CFG_ROW_MAJOR_UB = {AscendC::CO2Layout::ROW_MAJOR, true}; | ||
| 21 | +constexpr AscendC::FixpipeConfig CFG_NZ_UB = {AscendC::CO2Layout::NZ, true}; | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +namespace NpuArch::Gemm::Tile { | ||
| 25 | + | ||
| 26 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 27 | +struct CopyL0CToUBTla< | ||
| 28 | + NpuArch::Arch::AtlasA5, | ||
| 29 | + TensorSrc_, | ||
| 30 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 31 | + CopyL0CToUBMode::NO_SPLIT, | ||
| 32 | + ScaleGranularity::NO_QUANT, | ||
| 33 | + ReluEnable_, | ||
| 34 | + std::enable_if_t<tla::detail::isRowMajor<LayoutDst_>::value>> { | ||
| 35 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 36 | + using ElementDst = ElementDst_; | ||
| 37 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 38 | + static constexpr auto quantPre = | ||
| 39 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::NO_QUANT>::VALUE; | ||
| 40 | + static constexpr auto reluEn = ReluEnable_; | ||
| 41 | + | ||
| 42 | + template <class TensorDst, class TensorSrc> | ||
| 43 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint8_t unitFlag = 0) | ||
| 44 | + { | ||
| 45 | + static_assert( | ||
| 46 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 47 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 48 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and RowMajor" | ||
| 49 | + ); | ||
| 50 | + | ||
| 51 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams; | ||
| 52 | + | ||
| 53 | + // Fixpipe layout information | ||
| 54 | + intriParams.nSize = tla::get<1>(dstTensor.shape()); | ||
| 55 | + intriParams.mSize = tla::get<0>(dstTensor.shape()); | ||
| 56 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<0, 0>(srcTensor.stride()); | ||
| 57 | + intriParams.dstStride = tla::get<0>(dstTensor.stride()); | ||
| 58 | + | ||
| 59 | + // Fixpipe auxiliary arguments | ||
| 60 | + intriParams.quantPre = quantPre; | ||
| 61 | + intriParams.reluEn = reluEn; | ||
| 62 | + intriParams.unitFlag = unitFlag; | ||
| 63 | + | ||
| 64 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 65 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 66 | + | ||
| 67 | + // Call AscendC Fixpipe | ||
| 68 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 69 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + template <class TensorDst, class TensorSrc> | ||
| 73 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, bool subBlockId, uint8_t unitFlag = 0) | ||
| 74 | + { | ||
| 75 | + static_assert( | ||
| 76 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 77 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 78 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and RowMajor" | ||
| 79 | + ); | ||
| 80 | + | ||
| 81 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams; | ||
| 82 | + | ||
| 83 | + // Fixpipe layout information | ||
| 84 | + intriParams.nSize = tla::get<1>(dstTensor.shape()); | ||
| 85 | + intriParams.mSize = tla::get<0>(dstTensor.shape()); | ||
| 86 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<0, 0>(srcTensor.stride()); | ||
| 87 | + intriParams.dstStride = tla::get<0>(dstTensor.stride()); | ||
| 88 | + | ||
| 89 | + // Fixpipe auxiliary arguments | ||
| 90 | + intriParams.quantPre = quantPre; | ||
| 91 | + intriParams.reluEn = reluEn; | ||
| 92 | + intriParams.unitFlag = unitFlag; | ||
| 93 | + intriParams.dualDstCtl = 0; | ||
| 94 | + intriParams.subBlockId = subBlockId; | ||
| 95 | + | ||
| 96 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 97 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 98 | + | ||
| 99 | + // Call AscendC Fixpipe | ||
| 100 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 101 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 102 | + } | ||
| 103 | +}; | ||
| 104 | + | ||
| 105 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 106 | +struct CopyL0CToUBTla< | ||
| 107 | + NpuArch::Arch::AtlasA5, | ||
| 108 | + TensorSrc_, | ||
| 109 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 110 | + CopyL0CToUBMode::NO_SPLIT, | ||
| 111 | + ScaleGranularity::PER_TENSOR, | ||
| 112 | + ReluEnable_, | ||
| 113 | + std::enable_if_t<tla::detail::iszN<ElementDst_, LayoutDst_>::value>> { | ||
| 114 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 115 | + using ElementDst = ElementDst_; | ||
| 116 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 117 | + static constexpr auto quantPre = | ||
| 118 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::PER_TENSOR>::VALUE; | ||
| 119 | + static constexpr auto reluEn = ReluEnable_; | ||
| 120 | + | ||
| 121 | + struct Params { | ||
| 122 | + float scale = 1.0f; | ||
| 123 | + | ||
| 124 | + __aicore__ inline | ||
| 125 | + Params() = default; | ||
| 126 | + | ||
| 127 | + __aicore__ inline | ||
| 128 | + Params(float scalar) | ||
| 129 | + { | ||
| 130 | + scale = scalar; | ||
| 131 | + } | ||
| 132 | + }; | ||
| 133 | + Params params; | ||
| 134 | + | ||
| 135 | + __aicore__ inline | ||
| 136 | + CopyL0CToUBTla() = default; | ||
| 137 | + | ||
| 138 | + __aicore__ inline | ||
| 139 | + CopyL0CToUBTla(Params const ¶ms_) : params(params_) {}; | ||
| 140 | + | ||
| 141 | + template <class TensorDst, class TensorSrc> | ||
| 142 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint8_t unitFlag = 0) | ||
| 143 | + { | ||
| 144 | + static_assert( | ||
| 145 | + tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 146 | + && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 147 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 148 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and zN" | ||
| 149 | + ); | ||
| 150 | + | ||
| 151 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::NZ> intriParams; | ||
| 152 | + | ||
| 153 | + intriParams.nSize = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 154 | + intriParams.mSize = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 155 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<1, 0>(srcTensor.shape()); | ||
| 156 | + intriParams.dstStride = intriParams.mSize * (BYTE_PER_C0 / sizeof(ElementDst)); | ||
| 157 | + | ||
| 158 | + intriParams.quantPre = quantPre; | ||
| 159 | + intriParams.deqScalar = static_cast<uint64_t>(*reinterpret_cast<int32_t*>(¶ms.scale)); | ||
| 160 | + intriParams.reluEn = reluEn; | ||
| 161 | + intriParams.unitFlag = unitFlag; | ||
| 162 | + | ||
| 163 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 164 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 165 | + | ||
| 166 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_NZ_UB>( | ||
| 167 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + template <class TensorDst, class TensorSrc> | ||
| 171 | + __aicore__ inline void operator()( | ||
| 172 | + TensorDst const &dstTensor, TensorSrc const &srcTensor, bool subBlockId, uint8_t unitFlag = 0) | ||
| 173 | + { | ||
| 174 | + static_assert( | ||
| 175 | + tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 176 | + && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 177 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 178 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and zN" | ||
| 179 | + ); | ||
| 180 | + | ||
| 181 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::NZ> intriParams; | ||
| 182 | + | ||
| 183 | + intriParams.nSize = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 184 | + intriParams.mSize = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 185 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<1, 0>(srcTensor.shape()); | ||
| 186 | + intriParams.dstStride = intriParams.mSize * (BYTE_PER_C0 / sizeof(ElementDst)); | ||
| 187 | + | ||
| 188 | + intriParams.quantPre = quantPre; | ||
| 189 | + intriParams.deqScalar = static_cast<uint64_t>(*reinterpret_cast<int32_t*>(¶ms.scale)); | ||
| 190 | + intriParams.reluEn = reluEn; | ||
| 191 | + intriParams.unitFlag = unitFlag; | ||
| 192 | + intriParams.dualDstCtl = 0; | ||
| 193 | + intriParams.subBlockId = subBlockId; | ||
| 194 | + | ||
| 195 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 196 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 197 | + | ||
| 198 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_NZ_UB>( | ||
| 199 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 200 | + } | ||
| 201 | +}; | ||
| 202 | + | ||
| 203 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 204 | +struct CopyL0CToUBTla< | ||
| 205 | + NpuArch::Arch::AtlasA5, | ||
| 206 | + TensorSrc_, | ||
| 207 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 208 | + CopyL0CToUBMode::NO_SPLIT, | ||
| 209 | + ScaleGranularity::NO_QUANT, | ||
| 210 | + ReluEnable_, | ||
| 211 | + std::enable_if_t<tla::detail::iszN<ElementDst_, LayoutDst_>::value>> { | ||
| 212 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 213 | + using ElementDst = ElementDst_; | ||
| 214 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 215 | + static constexpr auto quantPre = | ||
| 216 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::NO_QUANT>::VALUE; | ||
| 217 | + static constexpr auto reluEn = ReluEnable_; | ||
| 218 | + | ||
| 219 | + template <class TensorDst, class TensorSrc> | ||
| 220 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint8_t unitFlag = 0) | ||
| 221 | + { | ||
| 222 | + static_assert( | ||
| 223 | + tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 224 | + && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 225 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 226 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and zN" | ||
| 227 | + ); | ||
| 228 | + | ||
| 229 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::NZ> intriParams; | ||
| 230 | + | ||
| 231 | + //shape = ((16, ceil_div(rows, 16)), (16, ceil_div(cols, 16))) | ||
| 232 | + //stride = ((16, 256), (1, round_up(rows, 16) * 16)) | ||
| 233 | + // zN/NZ Fixpipe consumes the physical fractal extent stored in TLA nested shape. | ||
| 234 | + // 源NZ矩阵在N方向上的大小 | ||
| 235 | + intriParams.nSize = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 236 | + // 源NZ矩阵在M方向上的大小 | ||
| 237 | + intriParams.mSize = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 238 | + // 源NZ矩阵中的相邻Z排布的起始地址偏移,单位是C0_SIZE | ||
| 239 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<1, 0>(srcTensor.shape()); | ||
| 240 | + // 目的NZ矩阵中相邻Z排布的起始地址偏移,单位是元素 | ||
| 241 | + intriParams.dstStride = intriParams.mSize * (BYTE_PER_C0 / sizeof(ElementDst)); | ||
| 242 | + | ||
| 243 | + intriParams.quantPre = quantPre; | ||
| 244 | + intriParams.reluEn = reluEn; | ||
| 245 | + intriParams.unitFlag = unitFlag; | ||
| 246 | + | ||
| 247 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 248 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 249 | + | ||
| 250 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_NZ_UB>( | ||
| 251 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + template <class TensorDst, class TensorSrc> | ||
| 255 | + __aicore__ inline void operator()( | ||
| 256 | + TensorDst const &dstTensor, TensorSrc const &srcTensor, bool subBlockId, uint8_t unitFlag = 0) | ||
| 257 | + { | ||
| 258 | + static_assert( | ||
| 259 | + tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 260 | + && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 261 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 262 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and zN" | ||
| 263 | + ); | ||
| 264 | + | ||
| 265 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::NZ> intriParams; | ||
| 266 | + | ||
| 267 | + intriParams.nSize = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 268 | + intriParams.mSize = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 269 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<1, 0>(srcTensor.shape()); | ||
| 270 | + intriParams.dstStride = intriParams.mSize * (BYTE_PER_C0 / sizeof(ElementDst)); | ||
| 271 | + | ||
| 272 | + intriParams.quantPre = quantPre; | ||
| 273 | + intriParams.reluEn = reluEn; | ||
| 274 | + intriParams.unitFlag = unitFlag; | ||
| 275 | + intriParams.dualDstCtl = 0; | ||
| 276 | + intriParams.subBlockId = subBlockId; | ||
| 277 | + | ||
| 278 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 279 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 280 | + | ||
| 281 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_NZ_UB>( | ||
| 282 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 283 | + } | ||
| 284 | +}; | ||
| 285 | + | ||
| 286 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 287 | +struct CopyL0CToUBTla< | ||
| 288 | + NpuArch::Arch::AtlasA5, | ||
| 289 | + TensorSrc_, | ||
| 290 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 291 | + CopyL0CToUBMode::NO_SPLIT, | ||
| 292 | + ScaleGranularity::PER_TENSOR, | ||
| 293 | + ReluEnable_, | ||
| 294 | + std::enable_if_t<tla::detail::isRowMajor<LayoutDst_>::value>> { | ||
| 295 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 296 | + using ElementDst = ElementDst_; | ||
| 297 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 298 | + static constexpr auto quantPre = | ||
| 299 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::PER_TENSOR>::VALUE; | ||
| 300 | + static constexpr auto reluEn = ReluEnable_; | ||
| 301 | + | ||
| 302 | + struct Params { | ||
| 303 | + float scale = 1.0f; | ||
| 304 | + | ||
| 305 | + __aicore__ inline | ||
| 306 | + Params() = default; | ||
| 307 | + | ||
| 308 | + __aicore__ inline | ||
| 309 | + Params(float scalar) | ||
| 310 | + { | ||
| 311 | + scale = scalar; | ||
| 312 | + } | ||
| 313 | + }; | ||
| 314 | + Params params; | ||
| 315 | + | ||
| 316 | + __aicore__ inline | ||
| 317 | + CopyL0CToUBTla() = default; | ||
| 318 | + | ||
| 319 | + __aicore__ inline | ||
| 320 | + CopyL0CToUBTla(Params const ¶ms_) : params(params_) {}; | ||
| 321 | + | ||
| 322 | + template <class TensorDst, class TensorSrc> | ||
| 323 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint8_t unitFlag = 0) | ||
| 324 | + { | ||
| 325 | + static_assert( | ||
| 326 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 327 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 328 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and RowMajor" | ||
| 329 | + ); | ||
| 330 | + | ||
| 331 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams; | ||
| 332 | + | ||
| 333 | + // Fixpipe layout information | ||
| 334 | + intriParams.nSize = tla::get<1>(dstTensor.shape()); | ||
| 335 | + intriParams.mSize = tla::get<0>(dstTensor.shape()); | ||
| 336 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<0, 0>(srcTensor.stride()); | ||
| 337 | + intriParams.dstStride = tla::get<0>(dstTensor.stride()); | ||
| 338 | + | ||
| 339 | + // Fixpipe auxiliary arguments | ||
| 340 | + intriParams.quantPre = quantPre; | ||
| 341 | + intriParams.deqScalar = static_cast<uint64_t>(*reinterpret_cast<int32_t*>(¶ms.scale)); | ||
| 342 | + intriParams.reluEn = reluEn; | ||
| 343 | + intriParams.unitFlag = unitFlag; | ||
| 344 | + | ||
| 345 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 346 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 347 | + | ||
| 348 | + // Call AscendC Fixpipe | ||
| 349 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 350 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 351 | + } | ||
| 352 | + template <class TensorDst, class TensorSrc> | ||
| 353 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, bool subBlockId, uint8_t unitFlag = 0) | ||
| 354 | + { | ||
| 355 | + static_assert( | ||
| 356 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 357 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 358 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and RowMajor" | ||
| 359 | + ); | ||
| 360 | + | ||
| 361 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams; | ||
| 362 | + | ||
| 363 | + // Fixpipe layout information | ||
| 364 | + intriParams.nSize = tla::get<1>(dstTensor.shape()); | ||
| 365 | + intriParams.mSize = tla::get<0>(dstTensor.shape()); | ||
| 366 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<0, 0>(srcTensor.stride()); | ||
| 367 | + intriParams.dstStride = tla::get<0>(dstTensor.stride()); | ||
| 368 | + | ||
| 369 | + // Fixpipe auxiliary arguments | ||
| 370 | + intriParams.quantPre = quantPre; | ||
| 371 | + intriParams.deqScalar = static_cast<uint64_t>(*reinterpret_cast<int32_t*>(¶ms.scale)); | ||
| 372 | + intriParams.reluEn = reluEn; | ||
| 373 | + intriParams.unitFlag = unitFlag; | ||
| 374 | + intriParams.dualDstCtl = 0; | ||
| 375 | + intriParams.subBlockId = subBlockId; | ||
| 376 | + | ||
| 377 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 378 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 379 | + | ||
| 380 | + // Call AscendC Fixpipe | ||
| 381 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 382 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 383 | + } | ||
| 384 | +}; | ||
| 385 | + | ||
| 386 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 387 | +struct CopyL0CToUBTla< | ||
| 388 | + NpuArch::Arch::AtlasA5, | ||
| 389 | + TensorSrc_, | ||
| 390 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 391 | + CopyL0CToUBMode::SPLIT_M, | ||
| 392 | + ScaleGranularity::NO_QUANT, | ||
| 393 | + ReluEnable_, | ||
| 394 | + std::enable_if_t<tla::detail::isRowMajor<LayoutDst_>::value>> { | ||
| 395 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 396 | + using ElementDst = ElementDst_; | ||
| 397 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 398 | + static constexpr auto quantPre = | ||
| 399 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::NO_QUANT>::VALUE; | ||
| 400 | + static constexpr auto reluEn = ReluEnable_; | ||
| 401 | + | ||
| 402 | + template <class TensorDst, class TensorSrc> | ||
| 403 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint8_t unitFlag = 0) | ||
| 404 | + { | ||
| 405 | + static_assert( | ||
| 406 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 407 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 408 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and RowMajor" | ||
| 409 | + ); | ||
| 410 | + | ||
| 411 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams; | ||
| 412 | + | ||
| 413 | + // Fixpipe layout information | ||
| 414 | + intriParams.nSize = tla::get<1>(dstTensor.shape()); | ||
| 415 | + intriParams.mSize = RoundUp(tla::get<0>(dstTensor.shape()), 2); // m must be even when spilt m | ||
| 416 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<0, 0>(srcTensor.stride()); | ||
| 417 | + intriParams.dstStride = tla::get<0>(dstTensor.stride()); | ||
| 418 | + | ||
| 419 | + // Fixpipe auxiliary arguments | ||
| 420 | + intriParams.quantPre = quantPre; | ||
| 421 | + intriParams.reluEn = reluEn; | ||
| 422 | + intriParams.unitFlag = unitFlag; | ||
| 423 | + intriParams.dualDstCtl = 1; | ||
| 424 | + | ||
| 425 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 426 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 427 | + | ||
| 428 | + // Call AscendC Fixpipe | ||
| 429 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 430 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 431 | + } | ||
| 432 | +}; | ||
| 433 | + | ||
| 434 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 435 | +struct CopyL0CToUBTla< | ||
| 436 | + NpuArch::Arch::AtlasA5, | ||
| 437 | + TensorSrc_, | ||
| 438 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 439 | + CopyL0CToUBMode::SPLIT_M, | ||
| 440 | + ScaleGranularity::NO_QUANT, | ||
| 441 | + ReluEnable_, | ||
| 442 | + std::enable_if_t<tla::detail::iszN<ElementDst_, LayoutDst_>::value>> { | ||
| 443 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 444 | + using ElementDst = ElementDst_; | ||
| 445 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 446 | + static constexpr auto quantPre = | ||
| 447 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::NO_QUANT>::VALUE; | ||
| 448 | + static constexpr auto reluEn = ReluEnable_; | ||
| 449 | + | ||
| 450 | + template <class TensorDst, class TensorSrc> | ||
| 451 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint8_t unitFlag = 0) | ||
| 452 | + { | ||
| 453 | + static_assert( | ||
| 454 | + tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 455 | + && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 456 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 457 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and zN" | ||
| 458 | + ); | ||
| 459 | + | ||
| 460 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::NZ> intriParams; | ||
| 461 | + | ||
| 462 | + intriParams.nSize = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 463 | + intriParams.mSize = RoundUp(tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()), 2); | ||
| 464 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<1, 0>(srcTensor.shape()); | ||
| 465 | + intriParams.dstStride = intriParams.mSize * (BYTE_PER_C0 / sizeof(ElementDst)); | ||
| 466 | + | ||
| 467 | + intriParams.quantPre = quantPre; | ||
| 468 | + intriParams.reluEn = reluEn; | ||
| 469 | + intriParams.unitFlag = unitFlag; | ||
| 470 | + intriParams.dualDstCtl = 1; | ||
| 471 | + | ||
| 472 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 473 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 474 | + | ||
| 475 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_NZ_UB>( | ||
| 476 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 477 | + } | ||
| 478 | +}; | ||
| 479 | + | ||
| 480 | +// NOTE: SPLIT_M + PER_CHANNEL is NOT supported by single Fixpipe with dualDstCtl=1, | ||
| 481 | +// because per-channel dequant (scale tensor) conflicts with dual-core split mode. | ||
| 482 | +// Workaround: manually decompose into two independent Fixpipe calls (sub0 + sub1), | ||
| 483 | +// each with a separate sub-tile and the same full scale tensor. | ||
| 484 | +// This keeps the dequantization correct while achieving dual-core output. | ||
| 485 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 486 | +struct CopyL0CToUBTla< | ||
| 487 | + NpuArch::Arch::AtlasA5, | ||
| 488 | + TensorSrc_, | ||
| 489 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 490 | + CopyL0CToUBMode::SPLIT_M, | ||
| 491 | + ScaleGranularity::PER_CHANNEL, | ||
| 492 | + ReluEnable_, | ||
| 493 | + std::enable_if_t<tla::detail::isRowMajor<LayoutDst_>::value>> { | ||
| 494 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 495 | + using ElementDst = ElementDst_; | ||
| 496 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 497 | + static constexpr auto quantPre = | ||
| 498 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::PER_CHANNEL>::VALUE; | ||
| 499 | + static constexpr auto reluEn = ReluEnable_; | ||
| 500 | + | ||
| 501 | + struct Params {}; | ||
| 502 | + Params params; | ||
| 503 | + | ||
| 504 | + __aicore__ inline | ||
| 505 | + CopyL0CToUBTla() = default; | ||
| 506 | + | ||
| 507 | + __aicore__ inline | ||
| 508 | + CopyL0CToUBTla(Params const ¶ms_) : params(params_) {}; | ||
| 509 | + | ||
| 510 | + template <class TensorDst, class TensorSrc> | ||
| 511 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, | ||
| 512 | + AscendC::LocalTensor<uint64_t> const &scale, uint8_t unitFlag = 0) | ||
| 513 | + { | ||
| 514 | + static_assert( | ||
| 515 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 516 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 517 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and RowMajor" | ||
| 518 | + ); | ||
| 519 | + | ||
| 520 | + uint32_t mSize = tla::get<0>(dstTensor.shape()); | ||
| 521 | + uint32_t nSize = tla::get<1>(dstTensor.shape()); | ||
| 522 | + uint32_t mPerSubCore = mSize / 2; | ||
| 523 | + | ||
| 524 | + // --- prepare sub-tiles for dual sub-core fixpipe --- | ||
| 525 | + // CAUTION: L0C srcTensor has a nested fractal shape (tuple<tuple<C<16>, uint>, tuple<C<16>, uint>>). | ||
| 526 | + // Do NOT use tla::get<1>(srcTensor.shape()) as MakeShape argument here, | ||
| 527 | + // because it returns a nested tuple fragment, not a flat uint. | ||
| 528 | + // Always pass flat uint values (nSize) to MakeShape; MakeLayoutTile handles the fractal mapping internally. | ||
| 529 | + auto dstSub0 = tla::GetTile(dstTensor, tla::MakeCoord(0, 0), tla::MakeShape(mPerSubCore, nSize)); | ||
| 530 | + auto srcSub0 = tla::GetTile(srcTensor, tla::MakeCoord(0, 0), tla::MakeShape(mPerSubCore, nSize)); | ||
| 531 | + | ||
| 532 | + auto dstSub1 = tla::GetTile(dstTensor, tla::MakeCoord(0, 0), tla::MakeShape(mPerSubCore, nSize)); | ||
| 533 | + auto srcSub1 = tla::GetTile(srcTensor, tla::MakeCoord(mPerSubCore, 0), tla::MakeShape(mPerSubCore, nSize)); | ||
| 534 | + | ||
| 535 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams0; | ||
| 536 | + intriParams0.nSize = tla::get<1>(dstSub0.shape()); | ||
| 537 | + intriParams0.mSize = tla::get<0>(dstSub0.shape()); | ||
| 538 | + intriParams0.srcStride = tla::get<1, 1>(srcSub0.stride()) / tla::get<0, 0>(srcSub0.stride()); | ||
| 539 | + intriParams0.dstStride = tla::get<0>(dstSub0.stride()); | ||
| 540 | + intriParams0.quantPre = quantPre; | ||
| 541 | + intriParams0.reluEn = reluEn; | ||
| 542 | + intriParams0.unitFlag = unitFlag; | ||
| 543 | + intriParams0.dualDstCtl = 0; | ||
| 544 | + intriParams0.subBlockId = 0; | ||
| 545 | + | ||
| 546 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams1; | ||
| 547 | + intriParams1.nSize = tla::get<1>(dstSub1.shape()); | ||
| 548 | + intriParams1.mSize = tla::get<0>(dstSub1.shape()); | ||
| 549 | + intriParams1.srcStride = tla::get<1, 1>(srcSub1.stride()) / tla::get<0, 0>(srcSub1.stride()); | ||
| 550 | + intriParams1.dstStride = tla::get<0>(dstSub1.stride()); | ||
| 551 | + intriParams1.quantPre = quantPre; | ||
| 552 | + intriParams1.reluEn = reluEn; | ||
| 553 | + intriParams1.unitFlag = unitFlag; | ||
| 554 | + intriParams1.dualDstCtl = 0; | ||
| 555 | + intriParams1.subBlockId = 1; | ||
| 556 | + | ||
| 557 | + // --- execute dual fixpipe for sub-core 0 and sub-core 1 --- | ||
| 558 | + auto dstOffset0 = dstSub0.layout()(dstSub0.coord()); | ||
| 559 | + auto srcOffset0 = srcSub0.layout()(srcSub0.coord()); | ||
| 560 | + auto dstOffset1 = dstSub1.layout()(dstSub1.coord()); | ||
| 561 | + auto srcOffset1 = srcSub1.layout()(srcSub1.coord()); | ||
| 562 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 563 | + dstSub0.data()[dstOffset0], srcSub0.data()[srcOffset0], scale, intriParams0); | ||
| 564 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 565 | + dstSub1.data()[dstOffset1], srcSub1.data()[srcOffset1], scale, intriParams1); | ||
| 566 | + } | ||
| 567 | +}; | ||
| 568 | + | ||
| 569 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 570 | +struct CopyL0CToUBTla< | ||
| 571 | + NpuArch::Arch::AtlasA5, | ||
| 572 | + TensorSrc_, | ||
| 573 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 574 | + CopyL0CToUBMode::SPLIT_M, | ||
| 575 | + ScaleGranularity::PER_CHANNEL, | ||
| 576 | + ReluEnable_, | ||
| 577 | + std::enable_if_t<tla::detail::iszN<ElementDst_, LayoutDst_>::value>> { | ||
| 578 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 579 | + using ElementDst = ElementDst_; | ||
| 580 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 581 | + static constexpr auto quantPre = | ||
| 582 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::PER_CHANNEL>::VALUE; | ||
| 583 | + static constexpr auto reluEn = ReluEnable_; | ||
| 584 | + | ||
| 585 | + struct Params {}; | ||
| 586 | + Params params; | ||
| 587 | + | ||
| 588 | + __aicore__ inline | ||
| 589 | + CopyL0CToUBTla() = default; | ||
| 590 | + | ||
| 591 | + __aicore__ inline | ||
| 592 | + CopyL0CToUBTla(Params const ¶ms_) : params(params_) {}; | ||
| 593 | + | ||
| 594 | + template <class TensorDst, class TensorSrc> | ||
| 595 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, | ||
| 596 | + AscendC::LocalTensor<uint64_t> const &scale, uint8_t unitFlag = 0) | ||
| 597 | + { | ||
| 598 | + static_assert( | ||
| 599 | + tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 600 | + && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 601 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 602 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and zN" | ||
| 603 | + ); | ||
| 604 | + | ||
| 605 | + uint32_t mSize = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 606 | + uint32_t nSize = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 607 | + uint32_t mPerSubCore = mSize / 2; | ||
| 608 | + | ||
| 609 | + auto dstSub0 = tla::GetTile(dstTensor, tla::MakeCoord(0, 0), tla::MakeShape(mPerSubCore, nSize)); | ||
| 610 | + auto srcSub0 = tla::GetTile(srcTensor, tla::MakeCoord(0, 0), tla::MakeShape(mPerSubCore, nSize)); | ||
| 611 | + | ||
| 612 | + auto dstSub1 = tla::GetTile(dstTensor, tla::MakeCoord(0, 0), tla::MakeShape(mPerSubCore, nSize)); | ||
| 613 | + auto srcSub1 = tla::GetTile(srcTensor, tla::MakeCoord(mPerSubCore, 0), tla::MakeShape(mPerSubCore, nSize)); | ||
| 614 | + | ||
| 615 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::NZ> intriParams0; | ||
| 616 | + intriParams0.nSize = tla::get<1, 0>(dstSub0.shape()) * tla::get<1, 1>(dstSub0.shape()); | ||
| 617 | + intriParams0.mSize = tla::get<0, 0>(dstSub0.shape()) * tla::get<0, 1>(dstSub0.shape()); | ||
| 618 | + intriParams0.srcStride = tla::get<1, 1>(srcSub0.stride()) / tla::get<1, 0>(srcSub0.shape()); | ||
| 619 | + intriParams0.dstStride = intriParams0.mSize * (BYTE_PER_C0 / sizeof(ElementDst)); | ||
| 620 | + intriParams0.quantPre = quantPre; | ||
| 621 | + intriParams0.reluEn = reluEn; | ||
| 622 | + intriParams0.unitFlag = unitFlag; | ||
| 623 | + intriParams0.dualDstCtl = 0; | ||
| 624 | + intriParams0.subBlockId = 0; | ||
| 625 | + | ||
| 626 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::NZ> intriParams1; | ||
| 627 | + intriParams1.nSize = tla::get<1, 0>(dstSub1.shape()) * tla::get<1, 1>(dstSub1.shape()); | ||
| 628 | + intriParams1.mSize = tla::get<0, 0>(dstSub1.shape()) * tla::get<0, 1>(dstSub1.shape()); | ||
| 629 | + intriParams1.srcStride = tla::get<1, 1>(srcSub1.stride()) / tla::get<1, 0>(srcSub1.shape()); | ||
| 630 | + intriParams1.dstStride = intriParams1.mSize * (BYTE_PER_C0 / sizeof(ElementDst)); | ||
| 631 | + intriParams1.quantPre = quantPre; | ||
| 632 | + intriParams1.reluEn = reluEn; | ||
| 633 | + intriParams1.unitFlag = unitFlag; | ||
| 634 | + intriParams1.dualDstCtl = 0; | ||
| 635 | + intriParams1.subBlockId = 1; | ||
| 636 | + | ||
| 637 | + auto dstOffset0 = dstSub0.layout()(dstSub0.coord()); | ||
| 638 | + auto srcOffset0 = srcSub0.layout()(srcSub0.coord()); | ||
| 639 | + auto dstOffset1 = dstSub1.layout()(dstSub1.coord()); | ||
| 640 | + auto srcOffset1 = srcSub1.layout()(srcSub1.coord()); | ||
| 641 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_NZ_UB>( | ||
| 642 | + dstSub0.data()[dstOffset0], srcSub0.data()[srcOffset0], scale, intriParams0); | ||
| 643 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_NZ_UB>( | ||
| 644 | + dstSub1.data()[dstOffset1], srcSub1.data()[srcOffset1], scale, intriParams1); | ||
| 645 | + } | ||
| 646 | +}; | ||
| 647 | + | ||
| 648 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 649 | +struct CopyL0CToUBTla< | ||
| 650 | + NpuArch::Arch::AtlasA5, | ||
| 651 | + TensorSrc_, | ||
| 652 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 653 | + CopyL0CToUBMode::SPLIT_N, | ||
| 654 | + ScaleGranularity::NO_QUANT, | ||
| 655 | + ReluEnable_, | ||
| 656 | + std::enable_if_t<tla::detail::isRowMajor<LayoutDst_>::value>> { | ||
| 657 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 658 | + using ElementDst = ElementDst_; | ||
| 659 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 660 | + static constexpr auto quantPre = | ||
| 661 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::NO_QUANT>::VALUE; | ||
| 662 | + static constexpr auto reluEn = ReluEnable_; | ||
| 663 | + | ||
| 664 | + template <class TensorDst, class TensorSrc> | ||
| 665 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint8_t unitFlag = 0) | ||
| 666 | + { | ||
| 667 | + static_assert( | ||
| 668 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 669 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 670 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and RowMajor" | ||
| 671 | + ); | ||
| 672 | + | ||
| 673 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams; | ||
| 674 | + | ||
| 675 | + // Fixpipe layout information | ||
| 676 | + intriParams.nSize = RoundUp(tla::get<1>(dstTensor.shape()), 32); | ||
| 677 | + intriParams.mSize = tla::get<0>(dstTensor.shape()); // m must be even when spilt m | ||
| 678 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<0, 0>(srcTensor.stride()); | ||
| 679 | + intriParams.dstStride = tla::get<0>(dstTensor.stride()); | ||
| 680 | + | ||
| 681 | + // Fixpipe auxiliary arguments | ||
| 682 | + intriParams.quantPre = quantPre; | ||
| 683 | + intriParams.reluEn = reluEn; | ||
| 684 | + intriParams.unitFlag = unitFlag; | ||
| 685 | + intriParams.dualDstCtl = 2; | ||
| 686 | + | ||
| 687 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 688 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 689 | + | ||
| 690 | + // Call AscendC Fixpipe | ||
| 691 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 692 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], intriParams); | ||
| 693 | + } | ||
| 694 | +}; | ||
| 695 | + | ||
| 696 | +template <class TensorSrc_, class ElementDst_, class LayoutDst_, class CoordDst_, bool ReluEnable_> | ||
| 697 | +struct CopyL0CToUBTla< | ||
| 698 | + NpuArch::Arch::AtlasA5, | ||
| 699 | + TensorSrc_, | ||
| 700 | + tla::Tensor<AscendC::LocalTensor<ElementDst_>, LayoutDst_, CoordDst_, AscendC::TPosition::VECCALC>, | ||
| 701 | + CopyL0CToUBMode::NO_SPLIT, | ||
| 702 | + ScaleGranularity::PER_CHANNEL, | ||
| 703 | + ReluEnable_, | ||
| 704 | + std::enable_if_t<tla::detail::isRowMajor<LayoutDst_>::value>> { | ||
| 705 | + using ArchTag = NpuArch::Arch::AtlasA5; | ||
| 706 | + using ElementDst = ElementDst_; | ||
| 707 | + using ElementSrc = typename TensorSrc_::Element; | ||
| 708 | + static constexpr auto quantPre = | ||
| 709 | + CopyL0CToDstQuantMode<ArchTag, ElementSrc, ElementDst, ScaleGranularity::PER_CHANNEL>::VALUE; | ||
| 710 | + static constexpr auto reluEn = ReluEnable_; | ||
| 711 | + | ||
| 712 | + struct Params {}; | ||
| 713 | + Params params; | ||
| 714 | + | ||
| 715 | + __aicore__ inline | ||
| 716 | + CopyL0CToUBTla() = default; | ||
| 717 | + | ||
| 718 | + __aicore__ inline | ||
| 719 | + CopyL0CToUBTla(Params const ¶ms_) : params(params_) {}; | ||
| 720 | + | ||
| 721 | + template <class TensorDst, class TensorSrc> | ||
| 722 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, | ||
| 723 | + AscendC::LocalTensor<uint64_t> const &scale, uint8_t unitFlag = 0) | ||
| 724 | + { | ||
| 725 | + static_assert( | ||
| 726 | + tla::detail::isRowMajor<typename TensorDst::Layout>::value && TensorSrc::position == AscendC::TPosition::CO1 | ||
| 727 | + && TensorDst::position == AscendC::TPosition::VECCALC, | ||
| 728 | + "The input parameters do not match. TensorSrc must be L0C, while TensorDst must be UB and RowMajor" | ||
| 729 | + ); | ||
| 730 | + | ||
| 731 | + AscendC::FixpipeParamsC310<AscendC::CO2Layout::ROW_MAJOR> intriParams; | ||
| 732 | + | ||
| 733 | + // Fixpipe layout information | ||
| 734 | + intriParams.nSize = tla::get<1>(dstTensor.shape()); | ||
| 735 | + intriParams.mSize = tla::get<0>(dstTensor.shape()); | ||
| 736 | + intriParams.srcStride = tla::get<1, 1>(srcTensor.stride()) / tla::get<0, 0>(srcTensor.stride()); | ||
| 737 | + intriParams.dstStride = tla::get<0>(dstTensor.stride()); | ||
| 738 | + | ||
| 739 | + // Fixpipe auxiliary arguments | ||
| 740 | + intriParams.quantPre = quantPre; | ||
| 741 | + intriParams.reluEn = reluEn; | ||
| 742 | + intriParams.unitFlag = unitFlag; | ||
| 743 | + | ||
| 744 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 745 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 746 | + | ||
| 747 | + // Call AscendC Fixpipe with scale tensor for per-channel quant | ||
| 748 | + AscendC::Fixpipe<ElementDst, ElementSrc, CFG_ROW_MAJOR_UB>( | ||
| 749 | + dstTensor.data()[dstOffset], srcTensor.data()[srcOffset], scale, intriParams); | ||
| 750 | + } | ||
| 751 | +}; | ||
| 752 | + | ||
| 753 | +///////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 754 | + | ||
| 755 | +} // namespace NpuArch::Gemm::Tile | ||
| 756 | + | ||
| 757 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/gemm/tile_common/copy_l1_to_bt.hpp+27-0
| @@ -0,0 +1,27 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace NpuArch::Gemm::Tile { | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +///////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 24 | + | ||
| 25 | +} // namespace NpuArch::Gemm::Tile | ||
| 26 | + | ||
| 27 | + | ||
| @@ -0,0 +1,349 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace NpuArch::Gemm::Tile { | ||
| 22 | + | ||
| 23 | +template < | ||
| 24 | + class ArchTag, | ||
| 25 | + class L1Type, | ||
| 26 | + class L0Type = void | ||
| 27 | +> | ||
| 28 | +struct CopyL1ToL0A { | ||
| 29 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy l1 to l0, can not find the specialization."); | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +//////////////////////////////// | ||
| 33 | +/// new add gemm | ||
| 34 | +template<class ArchTag, class Element> | ||
| 35 | +struct CopyL1ToL0A<ArchTag, NpuArch::Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>, NpuArch::Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::A2>>{ | ||
| 36 | + using LayoutDst = layout::zZ; | ||
| 37 | + using LayoutSrc = layout::zN; | ||
| 38 | + | ||
| 39 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 40 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 41 | + | ||
| 42 | + __aicore__ inline | ||
| 43 | + CopyL1ToL0A(){} | ||
| 44 | + | ||
| 45 | + __aicore__ inline | ||
| 46 | + void operator()( | ||
| 47 | + AscendC::LocalTensor<Element> dstTensor, | ||
| 48 | + AscendC::LocalTensor<Element> srcTensor, | ||
| 49 | + LayoutDst layoutDst, LayoutSrc layoutSrc | ||
| 50 | + ){ | ||
| 51 | + AscendC::LoadData2DParams loadDataParams; | ||
| 52 | + loadDataParams.startIndex = 0; | ||
| 53 | + loadDataParams.repeatTimes = static_cast<uint16_t>(layoutDst.shape(3)); | ||
| 54 | + loadDataParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_FRACTAL; | ||
| 55 | + loadDataParams.sid = 0; | ||
| 56 | + loadDataParams.dstGap = layoutDst.stride(3) / ELE_NUM_PER_FRACTAL - 1; | ||
| 57 | + loadDataParams.ifTranspose = false; | ||
| 58 | + loadDataParams.addrMode = 0; | ||
| 59 | + | ||
| 60 | + for (uint32_t i = 0; i < layoutDst.shape(1); i++) { | ||
| 61 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | +}; | ||
| 65 | + | ||
| 66 | +template<class ArchTag, class Element> | ||
| 67 | +struct CopyL1ToL0A<ArchTag, NpuArch::Gemm::GemmType<Element, layout::nN, AscendC::TPosition::A1>, NpuArch::Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::A2>>{ | ||
| 68 | + using LayoutDst = layout::zZ; | ||
| 69 | + using LayoutSrc = layout::nN; | ||
| 70 | + | ||
| 71 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 72 | + | ||
| 73 | + __aicore__ inline | ||
| 74 | + CopyL1ToL0A(){} | ||
| 75 | + | ||
| 76 | + __aicore__ inline | ||
| 77 | + void operator()( | ||
| 78 | + AscendC::LocalTensor<Element> dstTensor, | ||
| 79 | + AscendC::LocalTensor<Element> srcTensor, | ||
| 80 | + LayoutDst layoutDst, LayoutSrc layoutSrc | ||
| 81 | + ){ | ||
| 82 | + AscendC::LoadData2DParams loadDataParams; | ||
| 83 | + loadDataParams.startIndex = 0; | ||
| 84 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(1))); | ||
| 85 | + loadDataParams.srcStride = static_cast<uint16_t>(CeilDiv<ELE_NUM_PER_C0>(layoutSrc.orgShape(0)));; | ||
| 86 | + loadDataParams.sid = 0; | ||
| 87 | + loadDataParams.dstGap = 0; | ||
| 88 | + loadDataParams.ifTranspose = true; | ||
| 89 | + loadDataParams.addrMode = 0; | ||
| 90 | + for(uint32_t i = 0; i < CeilDiv<ELE_NUM_PER_C0>(layoutSrc.orgShape(0)); i++){ | ||
| 91 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | +}; | ||
| 95 | + | ||
| 96 | +template<class ArchTag> | ||
| 97 | +struct CopyL1ToL0A<ArchTag, NpuArch::Gemm::GemmType<float, layout::nN, AscendC::TPosition::A1>, NpuArch::Gemm::GemmType<float, layout::zZ, AscendC::TPosition::A2>>{ | ||
| 98 | + using Element = float; | ||
| 99 | + using LayoutDst = layout::zZ; | ||
| 100 | + using LayoutSrc = layout::nN; | ||
| 101 | + | ||
| 102 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 103 | + | ||
| 104 | + __aicore__ inline | ||
| 105 | + CopyL1ToL0A(){} | ||
| 106 | + | ||
| 107 | + __aicore__ inline | ||
| 108 | + void operator()( | ||
| 109 | + AscendC::LocalTensor<Element> dstTensor, | ||
| 110 | + AscendC::LocalTensor<Element> srcTensor, | ||
| 111 | + LayoutDst layoutDst, LayoutSrc layoutSrc | ||
| 112 | + ){ | ||
| 113 | + AscendC::LoadData2dTransposeParams loadDataParams; | ||
| 114 | + loadDataParams.startIndex = 0; | ||
| 115 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(1))); | ||
| 116 | + loadDataParams.srcStride = static_cast<uint16_t>(CeilDiv<C0_NUM_PER_FRACTAL>(layoutSrc.orgShape(0))); | ||
| 117 | + loadDataParams.dstGap = 1; | ||
| 118 | + loadDataParams.dstFracGap = 0; | ||
| 119 | + for(uint32_t i = 0; i < CeilDiv<C0_NUM_PER_FRACTAL>(layoutSrc.orgShape(0)); i++){ | ||
| 120 | + AscendC::LoadDataWithTranspose(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1) * 2], loadDataParams); | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | +}; | ||
| 124 | + | ||
| 125 | +template<class ArchTag> | ||
| 126 | +struct CopyL1ToL0A<ArchTag, NpuArch::Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::A1>, NpuArch::Gemm::GemmType<int8_t, layout::zZ, AscendC::TPosition::A2>>{ | ||
| 127 | + using Element = int8_t; | ||
| 128 | + using LayoutDst = layout::zZ; | ||
| 129 | + using LayoutSrc = layout::nZ; | ||
| 130 | + | ||
| 131 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 132 | + | ||
| 133 | + __aicore__ inline | ||
| 134 | + CopyL1ToL0A(){} | ||
| 135 | + | ||
| 136 | + __aicore__ inline | ||
| 137 | + void operator()( | ||
| 138 | + AscendC::LocalTensor<Element> dstTensor, | ||
| 139 | + AscendC::LocalTensor<Element> srcTensor, | ||
| 140 | + LayoutDst layoutDst, LayoutSrc layoutSrc | ||
| 141 | + ){ | ||
| 142 | + AscendC::LoadData2dTransposeParams loadDataParams; | ||
| 143 | + | ||
| 144 | + loadDataParams.startIndex = 0; | ||
| 145 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(1))); | ||
| 146 | + loadDataParams.srcStride = 1; | ||
| 147 | + loadDataParams.dstGap = 0; | ||
| 148 | + loadDataParams.dstFracGap = CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(1)) - 1; | ||
| 149 | + | ||
| 150 | + for (uint32_t i = 0; i < CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(0)); i++) { | ||
| 151 | + AscendC::LoadDataWithTranspose(dstTensor[i * layoutDst.stride(1) * 2], | ||
| 152 | + srcTensor[i * layoutSrc.stride(1)], | ||
| 153 | + loadDataParams); | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | +}; | ||
| 157 | +////////////////////////////////////////// | ||
| 158 | + | ||
| 159 | +/// Partial specialization for zN in and zZ out. | ||
| 160 | +template <class ArchTag, class Element> | ||
| 161 | +struct CopyL1ToL0A<ArchTag, Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>> { | ||
| 162 | + using LayoutDst = layout::zZ; | ||
| 163 | + using LayoutSrc = layout::zN; | ||
| 164 | + | ||
| 165 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 166 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 167 | + | ||
| 168 | + // Methods | ||
| 169 | + | ||
| 170 | + __aicore__ inline | ||
| 171 | + CopyL1ToL0A() {}; | ||
| 172 | + | ||
| 173 | + __aicore__ inline | ||
| 174 | + void operator()( | ||
| 175 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 176 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 177 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 178 | + { | ||
| 179 | + AscendC::LoadData2DParams loadDataParams; | ||
| 180 | + | ||
| 181 | + loadDataParams.startIndex = 0; | ||
| 182 | + loadDataParams.repeatTimes = static_cast<uint16_t>(layoutDst.shape(3)); | ||
| 183 | + loadDataParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_FRACTAL; | ||
| 184 | + loadDataParams.sid = 0; | ||
| 185 | + loadDataParams.dstGap = layoutDst.stride(3) / ELE_NUM_PER_FRACTAL - 1; | ||
| 186 | + loadDataParams.ifTranspose = false; | ||
| 187 | + loadDataParams.addrMode = 0; | ||
| 188 | + | ||
| 189 | + for (uint32_t i = 0; i < layoutDst.shape(1); i++) { | ||
| 190 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | +}; | ||
| 194 | + | ||
| 195 | +/// Partial specialization for float, zN in and zZ out. | ||
| 196 | +template <class ArchTag> | ||
| 197 | +struct CopyL1ToL0A<ArchTag, Gemm::GemmType<float, layout::zN, AscendC::TPosition::A1>> { | ||
| 198 | + using Element = float; | ||
| 199 | + using LayoutDst = layout::zZ; | ||
| 200 | + using LayoutSrc = layout::zN; | ||
| 201 | + | ||
| 202 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 203 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 204 | + | ||
| 205 | + // Methods | ||
| 206 | + | ||
| 207 | + __aicore__ inline | ||
| 208 | + CopyL1ToL0A() {}; | ||
| 209 | + | ||
| 210 | + __aicore__ inline | ||
| 211 | + void operator()( | ||
| 212 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 213 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 214 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 215 | + { | ||
| 216 | + constexpr uint8_t PAD_LIST[4] = {0, 0, 0, 0}; | ||
| 217 | + uint16_t l1M = layoutSrc.shape(0) * layoutSrc.shape(1); | ||
| 218 | + uint16_t l1K = layoutSrc.shape(2) * layoutSrc.shape(3); | ||
| 219 | + uint16_t l0M = layoutDst.shape(0) * layoutDst.shape(1); | ||
| 220 | + uint16_t l0K = layoutDst.shape(2) * layoutDst.shape(3); | ||
| 221 | + AscendC::SetFmatrix(1, l1M, PAD_LIST, AscendC::FmatrixMode::FMATRIX_LEFT); | ||
| 222 | + static constexpr AscendC::IsResetLoad3dConfig config = {false, false}; | ||
| 223 | + AscendC::LoadData3DParamsV2<Element> loadDataParams; | ||
| 224 | + loadDataParams.kExtension = l0K; | ||
| 225 | + loadDataParams.mExtension = l0M; | ||
| 226 | + loadDataParams.channelSize = l1K; | ||
| 227 | + | ||
| 228 | + AscendC::LoadData<Element, config>(dstTensor, srcTensor, loadDataParams); | ||
| 229 | + } | ||
| 230 | +}; | ||
| 231 | + | ||
| 232 | +template <class ArchTag, class Element> | ||
| 233 | +struct CopyL1ToL0A<ArchTag, Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>> { | ||
| 234 | + using LayoutDst = layout::zZ; | ||
| 235 | + using LayoutSrc = layout::nZ; | ||
| 236 | + | ||
| 237 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 238 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 239 | + | ||
| 240 | + __aicore__ inline | ||
| 241 | + CopyL1ToL0A() {}; | ||
| 242 | + | ||
| 243 | + __aicore__ inline | ||
| 244 | + void operator()( | ||
| 245 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 246 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 247 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 248 | + { | ||
| 249 | + AscendC::LoadData2DParams loadDataParams; | ||
| 250 | + | ||
| 251 | + loadDataParams.startIndex = 0; | ||
| 252 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(1))); | ||
| 253 | + loadDataParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_FRACTAL; | ||
| 254 | + loadDataParams.sid = 0; | ||
| 255 | + loadDataParams.dstGap = layoutDst.stride(3) / ELE_NUM_PER_FRACTAL - 1; | ||
| 256 | + loadDataParams.ifTranspose = true; | ||
| 257 | + loadDataParams.addrMode = 0; | ||
| 258 | + | ||
| 259 | + for (uint32_t i = 0; i < CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(0)); i++) { | ||
| 260 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 261 | + } | ||
| 262 | + } | ||
| 263 | +}; | ||
| 264 | + | ||
| 265 | +/// Partial specialization for int8_t, nZ in and zZ out. (Transpose A) | ||
| 266 | +template <class ArchTag> | ||
| 267 | +struct CopyL1ToL0A<ArchTag, Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::A1>> { | ||
| 268 | + using Element = int8_t; | ||
| 269 | + using LayoutDst = layout::zZ; | ||
| 270 | + using LayoutSrc = layout::nZ; | ||
| 271 | + | ||
| 272 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 273 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 274 | + | ||
| 275 | + // Methods | ||
| 276 | + | ||
| 277 | + __aicore__ inline | ||
| 278 | + CopyL1ToL0A() {}; | ||
| 279 | + | ||
| 280 | + __aicore__ inline | ||
| 281 | + void operator()( | ||
| 282 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 283 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 284 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 285 | + { | ||
| 286 | + AscendC::LoadData2dTransposeParams loadDataParams; | ||
| 287 | + | ||
| 288 | + loadDataParams.startIndex = 0; | ||
| 289 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(1))); | ||
| 290 | + loadDataParams.srcStride = 1; | ||
| 291 | + loadDataParams.dstGap = 0; | ||
| 292 | + loadDataParams.dstFracGap = CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(1)) - 1; | ||
| 293 | + | ||
| 294 | + for (uint32_t i = 0; i < CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(0)); i++) { | ||
| 295 | + AscendC::LoadDataWithTranspose(dstTensor[i * layoutDst.stride(1) * 2], | ||
| 296 | + srcTensor[i * layoutSrc.stride(1)], | ||
| 297 | + loadDataParams); | ||
| 298 | + } | ||
| 299 | + } | ||
| 300 | +}; | ||
| 301 | + | ||
| 302 | +/// Partial specialization for float, nZ in and zZ out. (Transpose A) | ||
| 303 | +template <class ArchTag> | ||
| 304 | +struct CopyL1ToL0A<ArchTag, Gemm::GemmType<float, layout::nZ, AscendC::TPosition::A1>> { | ||
| 305 | + using Element = float; | ||
| 306 | + using LayoutDst = layout::zZ; | ||
| 307 | + using LayoutSrc = layout::nZ; | ||
| 308 | + | ||
| 309 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 310 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 311 | + | ||
| 312 | + // Methods | ||
| 313 | + | ||
| 314 | + __aicore__ inline | ||
| 315 | + CopyL1ToL0A() {}; | ||
| 316 | + | ||
| 317 | + __aicore__ inline | ||
| 318 | + void operator()( | ||
| 319 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 320 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 321 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 322 | + { | ||
| 323 | + constexpr uint8_t PAD_LIST[4] = {0, 0, 0, 0}; | ||
| 324 | + uint16_t l1M = layoutSrc.shape(0) * layoutSrc.shape(1); | ||
| 325 | + uint16_t l1K = layoutSrc.shape(2) * layoutSrc.shape(3); | ||
| 326 | + uint16_t l0M = layoutDst.shape(0) * layoutDst.shape(1); | ||
| 327 | + uint16_t l0K = layoutDst.shape(2) * layoutDst.shape(3); | ||
| 328 | + // K, M need to be 16 aligned for f32 | ||
| 329 | + uint16_t l1MAlign = RoundUp<C0_NUM_PER_FRACTAL>(l1M); | ||
| 330 | + uint16_t l1KAlign = RoundUp<C0_NUM_PER_FRACTAL>(l1K); | ||
| 331 | + uint16_t l0MAlign = RoundUp<C0_NUM_PER_FRACTAL>(l0M); | ||
| 332 | + uint16_t l0KAlign = RoundUp<C0_NUM_PER_FRACTAL>(l0K); | ||
| 333 | + AscendC::SetFmatrix(1, l1KAlign, PAD_LIST, AscendC::FmatrixMode::FMATRIX_LEFT); | ||
| 334 | + static constexpr AscendC::IsResetLoad3dConfig config = {false, false}; | ||
| 335 | + AscendC::LoadData3DParamsV2<Element> loadDataParams; | ||
| 336 | + loadDataParams.kExtension = l0MAlign; | ||
| 337 | + loadDataParams.mExtension = l0KAlign; | ||
| 338 | + loadDataParams.enTranspose = true; | ||
| 339 | + loadDataParams.channelSize = l1MAlign; | ||
| 340 | + | ||
| 341 | + AscendC::LoadData<Element, config>(dstTensor, srcTensor, loadDataParams); | ||
| 342 | + } | ||
| 343 | +}; | ||
| 344 | + | ||
| 345 | +///////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 346 | + | ||
| 347 | +} // namespace NpuArch::Gemm::Tile | ||
| 348 | + | ||
| 349 | + | ||
| @@ -0,0 +1,335 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::Gemm::Tile { | ||
| 20 | + | ||
| 21 | +/// Partial specialization for CopyL1ToL0A, AtlasA5, zN in and zN out. | ||
| 22 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 23 | +struct TileCopyTla< | ||
| 24 | + Arch::AtlasA5, | ||
| 25 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::A1>, | ||
| 26 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::A2>, | ||
| 27 | + std::enable_if_t<tla::detail::iszN<ElementSrc, LayoutSrc>::value && tla::detail::iszN<ElementDst, LayoutDst>::value>> { | ||
| 28 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 29 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(ElementSrc); | ||
| 30 | + | ||
| 31 | + // Mehtods | ||
| 32 | + | ||
| 33 | + __aicore__ inline | ||
| 34 | + TileCopyTla() {}; | ||
| 35 | + | ||
| 36 | + template <class TensorDst, class TensorSrc> | ||
| 37 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 38 | + { | ||
| 39 | + static_assert( | ||
| 40 | + tla::detail::iszN<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 41 | + && tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 42 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::A2, | ||
| 43 | + "The input parameters do not match. TensorSrc must be L1 and zN, while TensorDst must be L0A and zN" | ||
| 44 | + ); | ||
| 45 | + | ||
| 46 | + const uint32_t dstOuterShapeRow = tla::get<0, 1>(dstTensor.shape()); | ||
| 47 | + const uint32_t dstOuterShapeCol = tla::get<1, 1>(dstTensor.shape()); | ||
| 48 | + const uint32_t srcOuterStrideCol = tla::get<1, 1>(srcTensor.stride()); | ||
| 49 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 50 | + auto srcCoord = srcTensor.coord(); | ||
| 51 | + | ||
| 52 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 53 | + loadDataParams.mStartPosition = CeilDiv<C0_NUM_PER_FRACTAL>(tla::get<0>(srcCoord)); | ||
| 54 | + loadDataParams.kStartPosition = CeilDiv<ELE_NUM_PER_C0>(tla::get<1>(srcCoord)); | ||
| 55 | + loadDataParams.mStep = dstOuterShapeRow; | ||
| 56 | + loadDataParams.kStep = dstOuterShapeCol; | ||
| 57 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideCol); | ||
| 58 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideCol); | ||
| 59 | + loadDataParams.ifTranspose = false; | ||
| 60 | + | ||
| 61 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 62 | + AscendC::LoadData(dstTensor.data()[dstOffset], srcTensor.data(), loadDataParams); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + template <class TensorDst, class TensorSrc> | ||
| 66 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint32_t l0Batch) | ||
| 67 | + { | ||
| 68 | + static_assert( | ||
| 69 | + tla::detail::iszN<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 70 | + && tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 71 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::A2, | ||
| 72 | + "The input parameters do not match. TensorSrc must be L1 and zN, while TensorDst must be L0A and zN" | ||
| 73 | + ); | ||
| 74 | + | ||
| 75 | + const uint32_t dstOuterShapeRow = tla::get<0, 1>(dstTensor.shape()); | ||
| 76 | + const uint32_t dstOuterShapeCol = tla::get<1, 1>(dstTensor.shape()); | ||
| 77 | + const uint32_t srcOuterStrideCol = tla::get<1, 1>(srcTensor.stride()); | ||
| 78 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 79 | + | ||
| 80 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 81 | + loadDataParams.mStartPosition = 0; | ||
| 82 | + loadDataParams.kStartPosition = 0; | ||
| 83 | + loadDataParams.mStep = dstOuterShapeRow; | ||
| 84 | + loadDataParams.kStep = dstOuterShapeCol * l0Batch; | ||
| 85 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideCol); | ||
| 86 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideCol); | ||
| 87 | + loadDataParams.ifTranspose = false; | ||
| 88 | + | ||
| 89 | + AscendC::LoadData(dstTensor.data(), srcTensor.data(), loadDataParams); | ||
| 90 | + } | ||
| 91 | +}; | ||
| 92 | + | ||
| 93 | +/// Partial specialization for CopyL1ToL0A, AtlasA5, not B8, nZ in and zN out. (Transpose A) | ||
| 94 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 95 | +struct TileCopyTla< | ||
| 96 | + Arch::AtlasA5, | ||
| 97 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::A1>, | ||
| 98 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::A2>, | ||
| 99 | + std::enable_if_t< | ||
| 100 | + !AscendC::Std::is_one_of_v<ElementSrc, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 101 | + !AscendC::Std::is_one_of_v<ElementDst, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 102 | + tla::detail::isnZ<ElementSrc, LayoutSrc>::value && tla::detail::iszN<ElementDst, LayoutDst>::value>> { | ||
| 103 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 104 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(ElementSrc); | ||
| 105 | + | ||
| 106 | + // Mehtods | ||
| 107 | + | ||
| 108 | + __aicore__ inline | ||
| 109 | + TileCopyTla() {}; | ||
| 110 | + | ||
| 111 | + template <class TensorDst, class TensorSrc> | ||
| 112 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 113 | + { | ||
| 114 | + static_assert( | ||
| 115 | + !AscendC::Std::is_one_of_v<typename TensorSrc::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 116 | + !AscendC::Std::is_one_of_v<typename TensorDst::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 117 | + tla::detail::isnZ<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 118 | + && tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 119 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::A2, | ||
| 120 | + "The input parameters do not match. TensorSrc must be L1 and nZ, while TensorDst must be L0A and zN" | ||
| 121 | + ); | ||
| 122 | + | ||
| 123 | + const uint32_t L0M = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 124 | + const uint32_t L0K = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 125 | + const uint32_t srcOuterStrideRow = tla::get<0, 1>(srcTensor.stride()); | ||
| 126 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 127 | + auto srcCoord = srcTensor.coord(); | ||
| 128 | + | ||
| 129 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 130 | + loadDataParams.mStartPosition = CeilDiv<C0_NUM_PER_FRACTAL>(tla::get<1>(srcCoord)); | ||
| 131 | + loadDataParams.kStartPosition = CeilDiv<ELE_NUM_PER_C0>(tla::get<0>(srcCoord)); | ||
| 132 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(L0K); | ||
| 133 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0M); | ||
| 134 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideRow); | ||
| 135 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideCol); | ||
| 136 | + loadDataParams.ifTranspose = true; | ||
| 137 | + | ||
| 138 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 139 | + AscendC::LoadData(dstTensor.data()[dstOffset], srcTensor.data(), loadDataParams); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + template <class TensorDst, class TensorSrc> | ||
| 143 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint32_t l0Batch) | ||
| 144 | + { | ||
| 145 | + static_assert( | ||
| 146 | + !AscendC::Std::is_one_of_v<typename TensorSrc::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 147 | + !AscendC::Std::is_one_of_v<typename TensorDst::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 148 | + tla::detail::isnZ<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 149 | + && tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 150 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::A2, | ||
| 151 | + "The input parameters do not match. TensorSrc must be L1 and nZ, while TensorDst must be L0A and zN" | ||
| 152 | + ); | ||
| 153 | + | ||
| 154 | + const uint32_t L1M = tla::get<0, 0>(srcTensor.shape()) * tla::get<0, 1>(srcTensor.shape()); | ||
| 155 | + const uint32_t L1K = tla::get<1, 0>(srcTensor.shape()) * tla::get<1, 1>(srcTensor.shape()); | ||
| 156 | + const uint32_t L0M = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 157 | + const uint32_t L0K = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 158 | + const uint32_t srcOuterStrideRow = tla::get<0, 1>(srcTensor.stride()); | ||
| 159 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 160 | + | ||
| 161 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 162 | + loadDataParams.mStartPosition = 0; | ||
| 163 | + loadDataParams.kStartPosition = 0; | ||
| 164 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(L0K); | ||
| 165 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0M); | ||
| 166 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideRow); | ||
| 167 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideCol); | ||
| 168 | + loadDataParams.ifTranspose = true; | ||
| 169 | + | ||
| 170 | + for (uint32_t l0BatchIdx = 0; l0BatchIdx < l0Batch; l0BatchIdx++) { | ||
| 171 | + AscendC::LoadData( | ||
| 172 | + dstTensor.data()[l0BatchIdx * L0M * L0K], srcTensor.data()[l0BatchIdx * L1M * L1K], loadDataParams | ||
| 173 | + ); | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | +}; | ||
| 177 | + | ||
| 178 | +/// Partial specialization for CopyL1ToL0A, AtlasA5, B8, nZ in and zN out. (Transpose A) | ||
| 179 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 180 | +struct TileCopyTla< | ||
| 181 | + Arch::AtlasA5, | ||
| 182 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::A1>, | ||
| 183 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::A2>, | ||
| 184 | + std::enable_if_t< | ||
| 185 | + AscendC::Std::is_one_of_v<ElementSrc, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 186 | + AscendC::Std::is_one_of_v<ElementDst, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 187 | + tla::detail::isnZ<ElementSrc, LayoutSrc>::value && tla::detail::iszN<ElementDst, LayoutDst>::value>> { | ||
| 188 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 189 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(ElementSrc); | ||
| 190 | + | ||
| 191 | + // Mehtods | ||
| 192 | + | ||
| 193 | + __aicore__ inline | ||
| 194 | + TileCopyTla() {}; | ||
| 195 | + | ||
| 196 | + template <class TensorDst, class TensorSrc> | ||
| 197 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 198 | + { | ||
| 199 | + static_assert( | ||
| 200 | + AscendC::Std::is_one_of_v<typename TensorSrc::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 201 | + AscendC::Std::is_one_of_v<typename TensorDst::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 202 | + tla::detail::isnZ<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 203 | + && tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 204 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::A2, | ||
| 205 | + "The input parameters do not match. TensorSrc must be L1 and nZ, while TensorDst must be L0A and zN" | ||
| 206 | + ); | ||
| 207 | + | ||
| 208 | + const uint32_t L0M = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 209 | + const uint32_t L0K = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 210 | + const uint32_t srcOuterStrideRow = tla::get<0, 1>(srcTensor.stride()); | ||
| 211 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 212 | + auto srcCoord = srcTensor.coord(); | ||
| 213 | + | ||
| 214 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 215 | + if (L0M % ELE_NUM_PER_C0 == 0) { | ||
| 216 | + loadDataParams.mStartPosition = CeilDiv<C0_NUM_PER_FRACTAL>(tla::get<1>(srcCoord)); | ||
| 217 | + loadDataParams.kStartPosition = CeilDiv<ELE_NUM_PER_C0>(tla::get<0>(srcCoord)); | ||
| 218 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(L0K); | ||
| 219 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0M); | ||
| 220 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideRow); | ||
| 221 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideCol); | ||
| 222 | + loadDataParams.ifTranspose = true; | ||
| 223 | + | ||
| 224 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 225 | + AscendC::LoadData(dstTensor.data()[dstOffset], srcTensor.data(), loadDataParams); | ||
| 226 | + } else { | ||
| 227 | + for (uint32_t kIdx = 0; kIdx < L0K / ELE_NUM_PER_C0; kIdx++) { | ||
| 228 | + loadDataParams.mStartPosition = CeilDiv<C0_NUM_PER_FRACTAL>(tla::get<1>(srcCoord)) + kIdx * 2; | ||
| 229 | + loadDataParams.kStartPosition = CeilDiv<ELE_NUM_PER_C0>(tla::get<0>(srcCoord)); | ||
| 230 | + loadDataParams.mStep = 2; | ||
| 231 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0M); | ||
| 232 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideRow); | ||
| 233 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideCol); | ||
| 234 | + loadDataParams.ifTranspose = true; | ||
| 235 | + | ||
| 236 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 237 | + AscendC::LoadData( | ||
| 238 | + dstTensor.data()[dstOffset + kIdx * L0M * ELE_NUM_PER_C0], srcTensor.data(), loadDataParams | ||
| 239 | + ); | ||
| 240 | + } | ||
| 241 | + } | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + template <class TensorDst, class TensorSrc> | ||
| 245 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint32_t l0Batch) | ||
| 246 | + { | ||
| 247 | + static_assert( | ||
| 248 | + AscendC::Std::is_one_of_v<typename TensorSrc::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 249 | + AscendC::Std::is_one_of_v<typename TensorDst::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 250 | + tla::detail::isnZ<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 251 | + && tla::detail::iszN<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 252 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::A2, | ||
| 253 | + "The input parameters do not match. TensorSrc must be L1 and nZ, while TensorDst must be L0A and zN" | ||
| 254 | + ); | ||
| 255 | + | ||
| 256 | + const uint32_t L1M = tla::get<0, 0>(srcTensor.shape()) * tla::get<0, 1>(srcTensor.shape()); | ||
| 257 | + const uint32_t L1K = tla::get<1, 0>(srcTensor.shape()) * tla::get<1, 1>(srcTensor.shape()); | ||
| 258 | + const uint32_t L0M = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 259 | + const uint32_t L0K = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 260 | + const uint32_t srcOuterStrideRow = tla::get<0, 1>(srcTensor.stride()); | ||
| 261 | + const uint32_t dstOuterStrideCol = tla::get<1, 1>(dstTensor.stride()); | ||
| 262 | + | ||
| 263 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 264 | + if (L0M % ELE_NUM_PER_C0 == 0) { | ||
| 265 | + loadDataParams.mStartPosition = 0; | ||
| 266 | + loadDataParams.kStartPosition = 0; | ||
| 267 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(L0K); | ||
| 268 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0M); | ||
| 269 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideRow); | ||
| 270 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideCol); | ||
| 271 | + loadDataParams.ifTranspose = true; | ||
| 272 | + | ||
| 273 | + for (uint32_t l0BatchIdx = 0; l0BatchIdx < l0Batch; l0BatchIdx++) { | ||
| 274 | + AscendC::LoadData( | ||
| 275 | + dstTensor.data()[l0BatchIdx * L0M * L0K], srcTensor.data()[l0BatchIdx * L1M * L1K], loadDataParams | ||
| 276 | + ); | ||
| 277 | + } | ||
| 278 | + } else { | ||
| 279 | + loadDataParams.mStartPosition = 0; | ||
| 280 | + loadDataParams.kStartPosition = 0; | ||
| 281 | + loadDataParams.mStep = 2; | ||
| 282 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0M); | ||
| 283 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideRow); | ||
| 284 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideCol); | ||
| 285 | + loadDataParams.ifTranspose = true; | ||
| 286 | + for (uint32_t l0BatchIdx = 0; l0BatchIdx < l0Batch; l0BatchIdx++) { | ||
| 287 | + for (uint32_t kIdx = 0; kIdx < L0K / ELE_NUM_PER_C0; kIdx++) { | ||
| 288 | + AscendC::LoadData( | ||
| 289 | + dstTensor.data()[l0BatchIdx * L0M * L0K + kIdx * L0M * ELE_NUM_PER_C0], | ||
| 290 | + srcTensor.data()[l0BatchIdx * L1M * L1K + kIdx * ELE_NUM_PER_FRACTAL * 2], loadDataParams | ||
| 291 | + ); | ||
| 292 | + } | ||
| 293 | + } | ||
| 294 | + } | ||
| 295 | + } | ||
| 296 | +}; | ||
| 297 | + | ||
| 298 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 299 | +struct TileCopyTla< | ||
| 300 | + Arch::AtlasA5, | ||
| 301 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::A1>, | ||
| 302 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::A2>, | ||
| 303 | + std::enable_if_t<tla::detail::isVector<LayoutSrc>::value>> { | ||
| 304 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 305 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(ElementSrc); | ||
| 306 | + | ||
| 307 | + __aicore__ inline | ||
| 308 | + TileCopyTla() {}; | ||
| 309 | + | ||
| 310 | + template <class TensorDst, class TensorSrc> | ||
| 311 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 312 | + { | ||
| 313 | + uint16_t aL1M = tla::get<0, 0>(srcTensor.stride()); | ||
| 314 | + uint16_t madM = tla::get<1, 1>(dstTensor.stride()); | ||
| 315 | + uint16_t madK = tla::get<1, 1>(dstTensor.shape()); | ||
| 316 | + | ||
| 317 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 318 | + loadDataParams.mStartPosition = 0; | ||
| 319 | + loadDataParams.kStartPosition = 0; | ||
| 320 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(madM); | ||
| 321 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(madK); | ||
| 322 | + loadDataParams.srcStride = CeilDiv<C0_NUM_PER_FRACTAL>(aL1M); | ||
| 323 | + loadDataParams.dstStride = CeilDiv<C0_NUM_PER_FRACTAL>(madM); | ||
| 324 | + | ||
| 325 | + loadDataParams.ifTranspose = false; | ||
| 326 | + auto srcOffset = srcTensor.layout()(srcTensor.coord()); | ||
| 327 | + AscendC::LoadData(dstTensor.data(), srcTensor.data()[srcOffset], loadDataParams); | ||
| 328 | + } | ||
| 329 | +}; | ||
| 330 | + | ||
| 331 | +///////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 332 | + | ||
| 333 | +} // namespace NpuArch::Gemm::Tile | ||
| 334 | + | ||
| 335 | + | ||
| @@ -0,0 +1,479 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace NpuArch::Gemm::Tile { | ||
| 21 | + | ||
| 22 | +template < | ||
| 23 | + class ArchTag, | ||
| 24 | + class L1Type, | ||
| 25 | + class L0Type = void | ||
| 26 | +> | ||
| 27 | +struct CopyL1ToL0B { | ||
| 28 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported copy l1 to l0, can not find the specialization."); | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +//////////////////////////////////////// | ||
| 32 | +/// new add gemm | ||
| 33 | +template<class ArchTag, class Element> | ||
| 34 | +struct CopyL1ToL0B<ArchTag, NpuArch::Gemm::GemmType<Element, layout::zZ, AscendC::TPosition::B1>, NpuArch::Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B2>>{ | ||
| 35 | + using LayoutDst = layout::nZ; | ||
| 36 | + using LayoutSrc = layout::zZ; | ||
| 37 | + | ||
| 38 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 39 | + | ||
| 40 | + __aicore__ inline | ||
| 41 | + CopyL1ToL0B(){} | ||
| 42 | + | ||
| 43 | + __aicore__ inline | ||
| 44 | + void operator()( | ||
| 45 | + AscendC::LocalTensor<Element> dstTensor, | ||
| 46 | + AscendC::LocalTensor<Element> srcTensor, | ||
| 47 | + LayoutDst layoutDst, LayoutSrc layoutSrc | ||
| 48 | + ){ | ||
| 49 | + AscendC::LoadData2DParams loadDataParams; | ||
| 50 | + loadDataParams.startIndex = 0; | ||
| 51 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<ELE_NUM_PER_C0>(layoutSrc.orgShape(1))); | ||
| 52 | + loadDataParams.srcStride = 1; | ||
| 53 | + loadDataParams.sid = 0; | ||
| 54 | + loadDataParams.dstGap = 0; | ||
| 55 | + loadDataParams.ifTranspose = true; | ||
| 56 | + loadDataParams.addrMode = 0; | ||
| 57 | + for(uint32_t i = 0; i < CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(0)); i++){ // K N | ||
| 58 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | +}; | ||
| 62 | + | ||
| 63 | +template<class ArchTag> | ||
| 64 | +struct CopyL1ToL0B<ArchTag, NpuArch::Gemm::GemmType<float, layout::zZ, AscendC::TPosition::B1>, NpuArch::Gemm::GemmType<float, layout::nZ, AscendC::TPosition::B2>>{ | ||
| 65 | + using Element = float; | ||
| 66 | + using LayoutDst = layout::nZ; | ||
| 67 | + using LayoutSrc = layout::zZ; | ||
| 68 | + | ||
| 69 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 70 | + | ||
| 71 | + __aicore__ inline | ||
| 72 | + CopyL1ToL0B(){} | ||
| 73 | + | ||
| 74 | + __aicore__ inline | ||
| 75 | + void operator()( | ||
| 76 | + AscendC::LocalTensor<Element> dstTensor, | ||
| 77 | + AscendC::LocalTensor<Element> srcTensor, | ||
| 78 | + LayoutDst layoutDst, LayoutSrc layoutSrc | ||
| 79 | + ){ | ||
| 80 | + AscendC::LoadData2dTransposeParams loadDataParams; | ||
| 81 | + loadDataParams.startIndex = 0; | ||
| 82 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<C0_NUM_PER_FRACTAL>(layoutSrc.orgShape(1))); | ||
| 83 | + loadDataParams.srcStride = 1; | ||
| 84 | + loadDataParams.dstGap = 0; | ||
| 85 | + loadDataParams.dstFracGap = static_cast<uint16_t>(CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(1))) - 1; | ||
| 86 | + for(uint32_t i = 0; i < CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(0)); i++){ // K N | ||
| 87 | + AscendC::LoadDataWithTranspose(dstTensor[i * layoutDst.stride(1) * 2], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | +}; | ||
| 91 | + | ||
| 92 | + | ||
| 93 | +template<class ArchTag> | ||
| 94 | +struct CopyL1ToL0B<ArchTag, NpuArch::Gemm::GemmType<int8_t, layout::zN, AscendC::TPosition::B1>, NpuArch::Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::B2>>{ | ||
| 95 | + using Element = int8_t; | ||
| 96 | + using LayoutDst = layout::nZ; | ||
| 97 | + using LayoutSrc = layout::zN; | ||
| 98 | + | ||
| 99 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 100 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 101 | + | ||
| 102 | + __aicore__ inline | ||
| 103 | + CopyL1ToL0B(){} | ||
| 104 | + | ||
| 105 | + __aicore__ inline | ||
| 106 | + void operator()( | ||
| 107 | + AscendC::LocalTensor<Element> dstTensor, | ||
| 108 | + AscendC::LocalTensor<Element> srcTensor, | ||
| 109 | + LayoutDst layoutDst, LayoutSrc layoutSrc | ||
| 110 | + ){ | ||
| 111 | + AscendC::LoadData2dTransposeParams loadDataParams; | ||
| 112 | + | ||
| 113 | + loadDataParams.startIndex = 0; | ||
| 114 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(1))); | ||
| 115 | + loadDataParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_FRACTAL / 2; | ||
| 116 | + loadDataParams.dstGap = 1; | ||
| 117 | + loadDataParams.dstFracGap = 0; | ||
| 118 | + | ||
| 119 | + for (uint32_t i = 0; i < CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(0)); i++) { | ||
| 120 | + AscendC::LoadDataWithTranspose(dstTensor[i * layoutDst.stride(1)], | ||
| 121 | + srcTensor[i * layoutSrc.stride(1) * 2], | ||
| 122 | + loadDataParams); | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | +}; | ||
| 126 | + | ||
| 127 | +template <class ArchTag, class Element> | ||
| 128 | +struct CopyL1ToL0B<ArchTag, NpuArch::Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B1>, NpuArch::Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::B2>> { | ||
| 129 | + using LayoutDst = layout::nZ; | ||
| 130 | + using LayoutSrc = layout::nZ; | ||
| 131 | + | ||
| 132 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 133 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 134 | + | ||
| 135 | + // Methods | ||
| 136 | + | ||
| 137 | + __aicore__ inline | ||
| 138 | + CopyL1ToL0B() {}; | ||
| 139 | + | ||
| 140 | + __aicore__ inline | ||
| 141 | + void operator()( | ||
| 142 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 143 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 144 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 145 | + { | ||
| 146 | + AscendC::LoadData2DParams loadDataParams; | ||
| 147 | + | ||
| 148 | + loadDataParams.startIndex = 0; | ||
| 149 | + loadDataParams.repeatTimes = static_cast<uint16_t>(layoutDst.shape(3)); | ||
| 150 | + loadDataParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_FRACTAL; | ||
| 151 | + loadDataParams.sid = 0; | ||
| 152 | + loadDataParams.dstGap = layoutDst.stride(3) / ELE_NUM_PER_FRACTAL - 1; | ||
| 153 | + loadDataParams.ifTranspose = false; | ||
| 154 | + loadDataParams.addrMode = 0; | ||
| 155 | + | ||
| 156 | + for (uint32_t i = 0; i < layoutDst.shape(1); i++) { | ||
| 157 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | +}; | ||
| 161 | +///////////////////////////////////////////// | ||
| 162 | + | ||
| 163 | +//////////////////////////////////////////// | ||
| 164 | +/// new add gemv | ||
| 165 | +template <class ArchTag, class Element> | ||
| 166 | +struct CopyL1ToL0B<ArchTag, NpuArch::Gemm::GemmType<Element, layout::zN, AscendC::TPosition::B1>, NpuArch::Gemm::GemmType<Element, layout::zN, AscendC::TPosition::B2>>{ | ||
| 167 | + using LayoutDst = layout::zN; | ||
| 168 | + using LayoutSrc = layout::zN; | ||
| 169 | + | ||
| 170 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 171 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 172 | + | ||
| 173 | + // Methods | ||
| 174 | + | ||
| 175 | + __aicore__ inline | ||
| 176 | + CopyL1ToL0B() {}; | ||
| 177 | + | ||
| 178 | + __aicore__ inline | ||
| 179 | + void operator()( | ||
| 180 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 181 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 182 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 183 | + { | ||
| 184 | + AscendC::LoadData2DParams loadDataParams; | ||
| 185 | + | ||
| 186 | + loadDataParams.startIndex = 0; | ||
| 187 | + loadDataParams.repeatTimes = static_cast<uint16_t>(layoutDst.shape(1)); | ||
| 188 | + loadDataParams.srcStride = layoutSrc.stride(1) / ELE_NUM_PER_FRACTAL; | ||
| 189 | + loadDataParams.sid = 0; | ||
| 190 | + loadDataParams.dstGap = layoutDst.stride(1) / ELE_NUM_PER_FRACTAL - 1; | ||
| 191 | + loadDataParams.ifTranspose = false; | ||
| 192 | + loadDataParams.addrMode = 0; | ||
| 193 | + | ||
| 194 | + for (uint32_t i = 0; i < layoutDst.shape(3); i++) | ||
| 195 | + { | ||
| 196 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(3)], srcTensor[i * layoutSrc.stride(3)], loadDataParams); | ||
| 197 | + } | ||
| 198 | + } | ||
| 199 | +}; | ||
| 200 | + | ||
| 201 | +template <class ArchTag, class Element> | ||
| 202 | +struct CopyL1ToL0B<ArchTag, NpuArch::Gemm::GemmType<Element, layout::nN, AscendC::TPosition::B1>, NpuArch::Gemm::GemmType<Element, layout::zN, AscendC::TPosition::B2>> | ||
| 203 | +{ | ||
| 204 | + using LayoutDst = layout::zN; | ||
| 205 | + using LayoutSrc = layout::nN; | ||
| 206 | + | ||
| 207 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 208 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 209 | + | ||
| 210 | + // Methods | ||
| 211 | + | ||
| 212 | + __aicore__ inline | ||
| 213 | + CopyL1ToL0B() {}; | ||
| 214 | + | ||
| 215 | + __aicore__ inline | ||
| 216 | + void operator()( | ||
| 217 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 218 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 219 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 220 | + { | ||
| 221 | + AscendC::LoadData2DParams loadDataParams; | ||
| 222 | + | ||
| 223 | + loadDataParams.startIndex = 0; | ||
| 224 | + loadDataParams.repeatTimes = layoutDst.shape(1) * layoutDst.shape(3); | ||
| 225 | + loadDataParams.srcStride = layoutSrc.stride(1) / ELE_NUM_PER_FRACTAL; | ||
| 226 | + loadDataParams.sid = 0; | ||
| 227 | + loadDataParams.dstGap = layoutDst.stride(1) / ELE_NUM_PER_FRACTAL - 1; | ||
| 228 | + loadDataParams.ifTranspose = true; | ||
| 229 | + loadDataParams.addrMode = 0; | ||
| 230 | + AscendC::LoadData(dstTensor, srcTensor, loadDataParams); | ||
| 231 | + }; | ||
| 232 | +}; | ||
| 233 | + | ||
| 234 | +template <class ArchTag> | ||
| 235 | +struct CopyL1ToL0B<ArchTag, NpuArch::Gemm::GemmType<float, layout::nN, AscendC::TPosition::B1>, NpuArch::Gemm::GemmType<float, layout::zN, AscendC::TPosition::B2>>{ | ||
| 236 | + using LayoutDst = layout::zN; | ||
| 237 | + using LayoutSrc = layout::nN; | ||
| 238 | + using Element = float; | ||
| 239 | + | ||
| 240 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 241 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 242 | + | ||
| 243 | + // Methods | ||
| 244 | + | ||
| 245 | + __aicore__ inline | ||
| 246 | + CopyL1ToL0B() {}; | ||
| 247 | + | ||
| 248 | + __aicore__ inline | ||
| 249 | + void operator()( | ||
| 250 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 251 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 252 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 253 | + { | ||
| 254 | + AscendC::LoadData2dTransposeParams loadDataParams; | ||
| 255 | + | ||
| 256 | + loadDataParams.startIndex = 0; | ||
| 257 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(0))); | ||
| 258 | + loadDataParams.srcStride = 1; | ||
| 259 | + loadDataParams.dstGap = 0; | ||
| 260 | + loadDataParams.dstFracGap = CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(0)) - 1; | ||
| 261 | + | ||
| 262 | + for (uint32_t i = 0; i < CeilDiv<2 * ELE_NUM_PER_C0>(layoutDst.orgShape(1)); i++) | ||
| 263 | + { | ||
| 264 | + AscendC::LoadDataWithTranspose( | ||
| 265 | + dstTensor[i * layoutDst.stride(3) * 2], | ||
| 266 | + srcTensor[i * layoutSrc.stride(3)], | ||
| 267 | + loadDataParams); | ||
| 268 | + } | ||
| 269 | + }; | ||
| 270 | +}; | ||
| 271 | + | ||
| 272 | +template <class ArchTag> | ||
| 273 | +struct CopyL1ToL0B<ArchTag, NpuArch::Gemm::GemmType<int8_t, layout::nZ, AscendC::TPosition::B1>, NpuArch::Gemm::GemmType<int8_t, layout::zN, AscendC::TPosition::B2>>{ | ||
| 274 | + using LayoutDst = layout::zN; | ||
| 275 | + using LayoutSrc = layout::nZ; | ||
| 276 | + using Element = int8_t; | ||
| 277 | + | ||
| 278 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 279 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 280 | + | ||
| 281 | + // Methods | ||
| 282 | + | ||
| 283 | + __aicore__ inline | ||
| 284 | + CopyL1ToL0B() {}; | ||
| 285 | + | ||
| 286 | + __aicore__ inline | ||
| 287 | + void operator()( | ||
| 288 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 289 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 290 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 291 | + { | ||
| 292 | + AscendC::LoadData2dTransposeParams loadDataParams; | ||
| 293 | + | ||
| 294 | + loadDataParams.startIndex = 0; | ||
| 295 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(0))); | ||
| 296 | + loadDataParams.srcStride = layoutSrc.stride(1) / ELE_NUM_PER_FRACTAL / 2; | ||
| 297 | + loadDataParams.dstGap = 1; | ||
| 298 | + loadDataParams.dstFracGap = 0; | ||
| 299 | + | ||
| 300 | + for (uint32_t i = 0; i < CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(1)); i++) | ||
| 301 | + { | ||
| 302 | + AscendC::LoadDataWithTranspose( | ||
| 303 | + dstTensor[i * layoutDst.stride(3)], | ||
| 304 | + srcTensor[i * layoutSrc.stride(3) * 2], | ||
| 305 | + loadDataParams); | ||
| 306 | + } | ||
| 307 | + } | ||
| 308 | +}; | ||
| 309 | +//////////////////////////////////////////// | ||
| 310 | + | ||
| 311 | +/// Partial specialization for int8_t, zN in and nZ out. | ||
| 312 | +template <class ArchTag> | ||
| 313 | +struct CopyL1ToL0B<ArchTag, Gemm::GemmType<int8_t, layout::zN, AscendC::TPosition::A1>> { | ||
| 314 | + using Element = int8_t; | ||
| 315 | + using LayoutDst = layout::nZ; | ||
| 316 | + using LayoutSrc = layout::zN; | ||
| 317 | + | ||
| 318 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 319 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 320 | + | ||
| 321 | + // Methods | ||
| 322 | + | ||
| 323 | + __aicore__ inline | ||
| 324 | + CopyL1ToL0B() {}; | ||
| 325 | + | ||
| 326 | + __aicore__ inline | ||
| 327 | + void operator()( | ||
| 328 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 329 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 330 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 331 | + { | ||
| 332 | + AscendC::LoadData2dTransposeParams loadDataParams; | ||
| 333 | + | ||
| 334 | + loadDataParams.startIndex = 0; | ||
| 335 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(1))); | ||
| 336 | + loadDataParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_FRACTAL / 2; | ||
| 337 | + loadDataParams.dstGap = 1; | ||
| 338 | + loadDataParams.dstFracGap = 0; | ||
| 339 | + | ||
| 340 | + for (uint32_t i = 0; i < CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(0)); i++) { | ||
| 341 | + AscendC::LoadDataWithTranspose(dstTensor[i * layoutDst.stride(1)], | ||
| 342 | + srcTensor[i * layoutSrc.stride(1) * 2], | ||
| 343 | + loadDataParams); | ||
| 344 | + } | ||
| 345 | + } | ||
| 346 | +}; | ||
| 347 | + | ||
| 348 | +/// Partial specialization for float, zN in and nZ out. | ||
| 349 | +template <class ArchTag> | ||
| 350 | +struct CopyL1ToL0B<ArchTag, Gemm::GemmType<float, layout::zN, AscendC::TPosition::A1>> { | ||
| 351 | + using Element = float; | ||
| 352 | + using LayoutDst = layout::nZ; | ||
| 353 | + using LayoutSrc = layout::zN; | ||
| 354 | + | ||
| 355 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 356 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 357 | + | ||
| 358 | + // Methods | ||
| 359 | + | ||
| 360 | + __aicore__ inline | ||
| 361 | + CopyL1ToL0B() {}; | ||
| 362 | + | ||
| 363 | + __aicore__ inline | ||
| 364 | + void operator()( | ||
| 365 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 366 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 367 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 368 | + { | ||
| 369 | + constexpr uint8_t PAD_LIST[4] = {0, 0, 0, 0}; | ||
| 370 | + uint16_t l1K = layoutSrc.shape(0) * layoutSrc.shape(1); | ||
| 371 | + uint16_t l1N = layoutSrc.shape(2) * layoutSrc.shape(3); | ||
| 372 | + uint16_t l0K = layoutDst.shape(0) * layoutDst.shape(1); | ||
| 373 | + uint16_t l0N = layoutDst.shape(2) * layoutDst.shape(3); | ||
| 374 | + // K, N need to be 16 aligned for f32 | ||
| 375 | + uint16_t l1KAlign = RoundUp<C0_NUM_PER_FRACTAL>(l1K); | ||
| 376 | + uint16_t l1NAlign = RoundUp<C0_NUM_PER_FRACTAL>(l1N); | ||
| 377 | + uint16_t l0KAlign = RoundUp<C0_NUM_PER_FRACTAL>(l0K); | ||
| 378 | + uint16_t l0NAlign = RoundUp<C0_NUM_PER_FRACTAL>(l0N); | ||
| 379 | + AscendC::SetFmatrix(1, l1KAlign, PAD_LIST, AscendC::FmatrixMode::FMATRIX_RIGHT); | ||
| 380 | + static constexpr AscendC::IsResetLoad3dConfig config = {false, false}; | ||
| 381 | + AscendC::LoadData3DParamsV2<Element> loadDataParams; | ||
| 382 | + loadDataParams.kExtension = l0NAlign; | ||
| 383 | + loadDataParams.mExtension = l0KAlign; | ||
| 384 | + loadDataParams.channelSize = l1NAlign; | ||
| 385 | + loadDataParams.fMatrixCtrl = true; | ||
| 386 | + | ||
| 387 | + AscendC::LoadData<Element, config>(dstTensor, srcTensor, loadDataParams); | ||
| 388 | + } | ||
| 389 | +}; | ||
| 390 | + | ||
| 391 | +/// Partial specialization for zN in and nZ out. | ||
| 392 | +template <class ArchTag, class Element> | ||
| 393 | +struct CopyL1ToL0B<ArchTag, Gemm::GemmType<Element, layout::zN, AscendC::TPosition::A1>> { | ||
| 394 | + using LayoutDst = layout::nZ; | ||
| 395 | + using LayoutSrc = layout::zN; | ||
| 396 | + | ||
| 397 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 398 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 399 | + | ||
| 400 | + // Methods | ||
| 401 | + | ||
| 402 | + __aicore__ inline | ||
| 403 | + CopyL1ToL0B() {}; | ||
| 404 | + | ||
| 405 | + __aicore__ inline | ||
| 406 | + void operator()( | ||
| 407 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 408 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 409 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 410 | + { | ||
| 411 | + AscendC::LoadData2DParams loadDataParams; | ||
| 412 | + | ||
| 413 | + loadDataParams.startIndex = 0; | ||
| 414 | + loadDataParams.repeatTimes = static_cast<uint16_t>(CeilDiv<ELE_NUM_PER_C0>(layoutDst.orgShape(1))); | ||
| 415 | + loadDataParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_FRACTAL; | ||
| 416 | + loadDataParams.sid = 0; | ||
| 417 | + loadDataParams.dstGap = layoutDst.stride(3) / ELE_NUM_PER_FRACTAL - 1; | ||
| 418 | + loadDataParams.ifTranspose = true; | ||
| 419 | + loadDataParams.addrMode = 0; | ||
| 420 | + | ||
| 421 | + for (uint32_t i = 0; i < CeilDiv<C0_NUM_PER_FRACTAL>(layoutDst.orgShape(0)); i++) { | ||
| 422 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 423 | + } | ||
| 424 | + } | ||
| 425 | +}; | ||
| 426 | + | ||
| 427 | +/// Partial specialization for nZ in and nZ out. (Transpose B) | ||
| 428 | +template <class ArchTag, class Element> | ||
| 429 | +struct CopyL1ToL0B<ArchTag, Gemm::GemmType<Element, layout::nZ, AscendC::TPosition::A1>> { | ||
| 430 | + using LayoutDst = layout::nZ; | ||
| 431 | + using LayoutSrc = layout::nZ; | ||
| 432 | + | ||
| 433 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 434 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 435 | + | ||
| 436 | + // Methods | ||
| 437 | + | ||
| 438 | + __aicore__ inline | ||
| 439 | + CopyL1ToL0B() {}; | ||
| 440 | + | ||
| 441 | + __aicore__ inline | ||
| 442 | + void operator()( | ||
| 443 | + AscendC::LocalTensor<Element> const &dstTensor, | ||
| 444 | + AscendC::LocalTensor<Element> const &srcTensor, | ||
| 445 | + LayoutDst const &layoutDst, LayoutSrc const &layoutSrc) | ||
| 446 | + { | ||
| 447 | + AscendC::LoadData2DParams loadDataParams; | ||
| 448 | + if (layoutSrc.shape(3) == layoutDst.shape(3)) { | ||
| 449 | + loadDataParams.startIndex = 0; | ||
| 450 | + loadDataParams.repeatTimes = static_cast<uint16_t>(layoutDst.shape(1) * layoutDst.shape(3)); | ||
| 451 | + loadDataParams.srcStride = 1; | ||
| 452 | + loadDataParams.sid = 0; | ||
| 453 | + loadDataParams.dstGap = 0; | ||
| 454 | + loadDataParams.ifTranspose = false; | ||
| 455 | + loadDataParams.addrMode = 0; | ||
| 456 | + | ||
| 457 | + AscendC::LoadData(dstTensor, srcTensor, loadDataParams); | ||
| 458 | + } else { | ||
| 459 | + loadDataParams.startIndex = 0; | ||
| 460 | + loadDataParams.repeatTimes = static_cast<uint16_t>(layoutDst.shape(3)); | ||
| 461 | + loadDataParams.srcStride = layoutSrc.stride(3) / ELE_NUM_PER_FRACTAL; | ||
| 462 | + loadDataParams.sid = 0; | ||
| 463 | + loadDataParams.dstGap = layoutDst.stride(3) / ELE_NUM_PER_FRACTAL - 1; | ||
| 464 | + loadDataParams.ifTranspose = false; | ||
| 465 | + loadDataParams.addrMode = 0; | ||
| 466 | + | ||
| 467 | + for (uint32_t i = 0; i < layoutDst.shape(1); i++) { | ||
| 468 | + AscendC::LoadData(dstTensor[i * layoutDst.stride(1)], srcTensor[i * layoutSrc.stride(1)], loadDataParams); | ||
| 469 | + } | ||
| 470 | + } | ||
| 471 | + | ||
| 472 | + } | ||
| 473 | +}; | ||
| 474 | + | ||
| 475 | +///////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 476 | + | ||
| 477 | +} // namespace NpuArch::Gemm::Tile | ||
| 478 | + | ||
| 479 | + | ||
| @@ -0,0 +1,302 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::Gemm::Tile { | ||
| 20 | + | ||
| 21 | +/// Partial specialization for CopyL1ToL0B, AtlasA5, not B8, zN in and nZ out. | ||
| 22 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 23 | +struct TileCopyTla< | ||
| 24 | + Arch::AtlasA5, | ||
| 25 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::A1>, | ||
| 26 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::B2>, | ||
| 27 | + std::enable_if_t< | ||
| 28 | + !AscendC::Std::is_one_of_v<ElementSrc, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 29 | + !AscendC::Std::is_one_of_v<ElementDst, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 30 | + tla::detail::iszN<ElementSrc, LayoutSrc>::value && tla::detail::isnZ<ElementDst, LayoutDst>::value>> { | ||
| 31 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 32 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(ElementSrc); | ||
| 33 | + | ||
| 34 | + // Mehtods | ||
| 35 | + | ||
| 36 | + __aicore__ inline | ||
| 37 | + TileCopyTla() {}; | ||
| 38 | + | ||
| 39 | + template <class TensorDst, class TensorSrc> | ||
| 40 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 41 | + { | ||
| 42 | + static_assert( | ||
| 43 | + !AscendC::Std::is_one_of_v<typename TensorSrc::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 44 | + !AscendC::Std::is_one_of_v<typename TensorDst::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 45 | + tla::detail::iszN<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 46 | + && tla::detail::isnZ<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 47 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::B2, | ||
| 48 | + "The input parameters do not match. TensorSrc must be L1 and zN, while TensorDst must be L0B and nZ" | ||
| 49 | + ); | ||
| 50 | + | ||
| 51 | + const uint32_t L0K = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 52 | + const uint32_t L0N = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 53 | + const uint32_t srcOuterStrideCol = tla::get<1, 1>(srcTensor.stride()); | ||
| 54 | + const uint32_t dstOuterStrideRow = tla::get<0, 1>(dstTensor.stride()); | ||
| 55 | + auto srcCoord = srcTensor.coord(); | ||
| 56 | + | ||
| 57 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 58 | + loadDataParams.mStartPosition = CeilDiv<C0_NUM_PER_FRACTAL>(tla::get<0>(srcCoord)); | ||
| 59 | + loadDataParams.kStartPosition = CeilDiv<ELE_NUM_PER_C0>(tla::get<1>(srcCoord)); | ||
| 60 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(L0K); | ||
| 61 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0N); | ||
| 62 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideCol); | ||
| 63 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideRow); | ||
| 64 | + loadDataParams.ifTranspose = true; | ||
| 65 | + | ||
| 66 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 67 | + AscendC::LoadData(dstTensor.data()[dstOffset], srcTensor.data(), loadDataParams); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + template <class TensorDst, class TensorSrc> | ||
| 71 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint32_t l0Batch) | ||
| 72 | + { | ||
| 73 | + static_assert( | ||
| 74 | + !AscendC::Std::is_one_of_v<typename TensorSrc::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 75 | + !AscendC::Std::is_one_of_v<typename TensorDst::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 76 | + tla::detail::iszN<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 77 | + && tla::detail::isnZ<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 78 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::B2, | ||
| 79 | + "The input parameters do not match. TensorSrc must be L1 and zN, while TensorDst must be L0B and nZ" | ||
| 80 | + ); | ||
| 81 | + | ||
| 82 | + const uint32_t L1K = tla::get<0, 0>(srcTensor.shape()) * tla::get<0, 1>(srcTensor.shape()); | ||
| 83 | + const uint32_t L1N = tla::get<1, 0>(srcTensor.shape()) * tla::get<1, 1>(srcTensor.shape()); | ||
| 84 | + const uint32_t L0K = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 85 | + const uint32_t L0N = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 86 | + const uint32_t srcOuterStrideCol = tla::get<1, 1>(srcTensor.stride()); | ||
| 87 | + const uint32_t dstOuterStrideRow = tla::get<0, 1>(dstTensor.stride()); | ||
| 88 | + | ||
| 89 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 90 | + loadDataParams.mStartPosition = 0; | ||
| 91 | + loadDataParams.kStartPosition = 0; | ||
| 92 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(L0K); | ||
| 93 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0N); | ||
| 94 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideCol); | ||
| 95 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideRow); | ||
| 96 | + loadDataParams.ifTranspose = true; | ||
| 97 | + | ||
| 98 | + for (uint32_t l0BatchIdx = 0; l0BatchIdx < l0Batch; l0BatchIdx++) { | ||
| 99 | + AscendC::LoadData( | ||
| 100 | + dstTensor.data()[l0BatchIdx * L0N * L0K], srcTensor.data()[l0BatchIdx * L1N * L1K], loadDataParams | ||
| 101 | + ); | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | +}; | ||
| 105 | + | ||
| 106 | +/// Partial specialization for CopyL1ToL0B, AtlasA5, B8, zN in and nZ out. | ||
| 107 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 108 | +struct TileCopyTla< | ||
| 109 | + Arch::AtlasA5, | ||
| 110 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::A1>, | ||
| 111 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::B2>, | ||
| 112 | + std::enable_if_t< | ||
| 113 | + AscendC::Std::is_one_of_v<ElementSrc, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 114 | + AscendC::Std::is_one_of_v<ElementDst, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 115 | + tla::detail::iszN<ElementSrc, LayoutSrc>::value && tla::detail::isnZ<ElementDst, LayoutDst>::value>> { | ||
| 116 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 117 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(ElementSrc); | ||
| 118 | + | ||
| 119 | + // Mehtods | ||
| 120 | + | ||
| 121 | + __aicore__ inline | ||
| 122 | + TileCopyTla() {}; | ||
| 123 | + | ||
| 124 | + template <class TensorDst, class TensorSrc> | ||
| 125 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 126 | + { | ||
| 127 | + static_assert( | ||
| 128 | + AscendC::Std::is_one_of_v<typename TensorSrc::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 129 | + AscendC::Std::is_one_of_v<typename TensorDst::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 130 | + tla::detail::iszN<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 131 | + && tla::detail::isnZ<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 132 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::B2, | ||
| 133 | + "The input parameters do not match. TensorSrc must be L1 and zN, while TensorDst must be L0B and nZ" | ||
| 134 | + ); | ||
| 135 | + | ||
| 136 | + const uint32_t L0K = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 137 | + const uint32_t L0N = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 138 | + const uint32_t srcOuterStrideCol = tla::get<1, 1>(srcTensor.stride()); | ||
| 139 | + const uint32_t dstOuterStrideRow = tla::get<0, 1>(dstTensor.stride()); | ||
| 140 | + auto srcCoord = srcTensor.coord(); | ||
| 141 | + | ||
| 142 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 143 | + if (L0N % ELE_NUM_PER_C0 == 0) { | ||
| 144 | + loadDataParams.mStartPosition = CeilDiv<C0_NUM_PER_FRACTAL>(tla::get<0>(srcCoord)); | ||
| 145 | + loadDataParams.kStartPosition = CeilDiv<ELE_NUM_PER_C0>(tla::get<1>(srcCoord)); | ||
| 146 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(L0K); | ||
| 147 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0N); | ||
| 148 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideCol); | ||
| 149 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideRow); | ||
| 150 | + loadDataParams.ifTranspose = true; | ||
| 151 | + | ||
| 152 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 153 | + AscendC::LoadData(dstTensor.data()[dstOffset], srcTensor.data(), loadDataParams); | ||
| 154 | + } else { | ||
| 155 | + for (uint32_t kIdx = 0; kIdx < L0K / ELE_NUM_PER_C0; kIdx++) { | ||
| 156 | + loadDataParams.mStartPosition = CeilDiv<C0_NUM_PER_FRACTAL>(tla::get<0>(srcCoord)) + kIdx * 2; | ||
| 157 | + loadDataParams.kStartPosition = CeilDiv<ELE_NUM_PER_C0>(tla::get<1>(srcCoord)); | ||
| 158 | + loadDataParams.mStep = 2; | ||
| 159 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0N); | ||
| 160 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideCol); | ||
| 161 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideRow); | ||
| 162 | + loadDataParams.ifTranspose = true; | ||
| 163 | + | ||
| 164 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 165 | + AscendC::LoadData( | ||
| 166 | + dstTensor.data()[dstOffset + kIdx * L0N * ELE_NUM_PER_C0], srcTensor.data(), loadDataParams | ||
| 167 | + ); | ||
| 168 | + } | ||
| 169 | + } | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + template <class TensorDst, class TensorSrc> | ||
| 173 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint32_t l0Batch) | ||
| 174 | + { | ||
| 175 | + static_assert( | ||
| 176 | + AscendC::Std::is_one_of_v<typename TensorSrc::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 177 | + AscendC::Std::is_one_of_v<typename TensorDst::Element, int8_t, float8_e4m3_t, float8_e5m2_t> && | ||
| 178 | + tla::detail::iszN<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 179 | + && tla::detail::isnZ<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 180 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::B2, | ||
| 181 | + "The input parameters do not match. TensorSrc must be L1 and zN, while TensorDst must be L0B and nZ" | ||
| 182 | + ); | ||
| 183 | + | ||
| 184 | + const uint32_t L1K = tla::get<0, 0>(srcTensor.shape()) * tla::get<0, 1>(srcTensor.shape()); | ||
| 185 | + const uint32_t L1N = tla::get<1, 0>(srcTensor.shape()) * tla::get<1, 1>(srcTensor.shape()); | ||
| 186 | + const uint32_t L0K = tla::get<0, 0>(dstTensor.shape()) * tla::get<0, 1>(dstTensor.shape()); | ||
| 187 | + const uint32_t L0N = tla::get<1, 0>(dstTensor.shape()) * tla::get<1, 1>(dstTensor.shape()); | ||
| 188 | + const uint32_t srcOuterStrideCol = tla::get<1, 1>(srcTensor.stride()); | ||
| 189 | + const uint32_t dstOuterStrideRow = tla::get<0, 1>(dstTensor.stride()); | ||
| 190 | + | ||
| 191 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 192 | + if (L0N % ELE_NUM_PER_C0 == 0) { | ||
| 193 | + loadDataParams.mStartPosition = 0; | ||
| 194 | + loadDataParams.kStartPosition = 0; | ||
| 195 | + loadDataParams.mStep = CeilDiv<C0_NUM_PER_FRACTAL>(L0K); | ||
| 196 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0N); | ||
| 197 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideCol); | ||
| 198 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideRow); | ||
| 199 | + loadDataParams.ifTranspose = true; | ||
| 200 | + | ||
| 201 | + for (uint32_t l0BatchIdx = 0; l0BatchIdx < l0Batch; l0BatchIdx++) { | ||
| 202 | + AscendC::LoadData( | ||
| 203 | + dstTensor.data()[l0BatchIdx * L0N * L0K], srcTensor.data()[l0BatchIdx * L1N * L1K], loadDataParams | ||
| 204 | + ); | ||
| 205 | + } | ||
| 206 | + } else { | ||
| 207 | + loadDataParams.mStartPosition = 0; | ||
| 208 | + loadDataParams.kStartPosition = 0; | ||
| 209 | + loadDataParams.mStep = 2; | ||
| 210 | + loadDataParams.kStep = CeilDiv<ELE_NUM_PER_C0>(L0N); | ||
| 211 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideCol); | ||
| 212 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideRow); | ||
| 213 | + loadDataParams.ifTranspose = true; | ||
| 214 | + for (uint32_t l0BatchIdx = 0; l0BatchIdx < l0Batch; l0BatchIdx++) { | ||
| 215 | + for (uint32_t kIdx = 0; kIdx < L0K / ELE_NUM_PER_C0; kIdx++) { | ||
| 216 | + AscendC::LoadData( | ||
| 217 | + dstTensor.data()[l0BatchIdx * L0N * L0K + kIdx * L0N * ELE_NUM_PER_C0], | ||
| 218 | + srcTensor.data()[l0BatchIdx * L1N * L1K + kIdx * ELE_NUM_PER_FRACTAL * 2], loadDataParams | ||
| 219 | + ); | ||
| 220 | + } | ||
| 221 | + } | ||
| 222 | + } | ||
| 223 | + } | ||
| 224 | +}; | ||
| 225 | + | ||
| 226 | +/// Partial specialization for CopyL1ToL0B, AtlasA5, nZ in and nZ out. (Transpose B) | ||
| 227 | +template <class ElementSrc, class ElementDst, class LayoutSrc, class LayoutDst, class CoordSrc, class CoordDst> | ||
| 228 | +struct TileCopyTla< | ||
| 229 | + Arch::AtlasA5, | ||
| 230 | + tla::Tensor<AscendC::LocalTensor<ElementSrc>, LayoutSrc, CoordSrc, AscendC::TPosition::A1>, | ||
| 231 | + tla::Tensor<AscendC::LocalTensor<ElementDst>, LayoutDst, CoordDst, AscendC::TPosition::B2>, | ||
| 232 | + std::enable_if_t<tla::detail::isnZ<ElementSrc, LayoutSrc>::value && tla::detail::isnZ<ElementDst, LayoutDst>::value>> { | ||
| 233 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(ElementSrc); | ||
| 234 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(ElementSrc); | ||
| 235 | + | ||
| 236 | + // Mehtods | ||
| 237 | + | ||
| 238 | + __aicore__ inline | ||
| 239 | + TileCopyTla() {}; | ||
| 240 | + | ||
| 241 | + template <class TensorDst, class TensorSrc> | ||
| 242 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor) | ||
| 243 | + { | ||
| 244 | + static_assert( | ||
| 245 | + tla::detail::isnZ<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 246 | + && tla::detail::isnZ<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 247 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::B2, | ||
| 248 | + "The input parameters do not match. TensorSrc must be L1 and nZ, while TensorDst must be L0B and nZ" | ||
| 249 | + ); | ||
| 250 | + | ||
| 251 | + const uint32_t dstOuterShapeRow = tla::get<0, 1>(dstTensor.shape()); | ||
| 252 | + const uint32_t dstOuterShapeCol = tla::get<1, 1>(dstTensor.shape()); | ||
| 253 | + const uint32_t srcOuterStrideRow = tla::get<0, 1>(srcTensor.stride()); | ||
| 254 | + const uint32_t dstOuterStrideRow = tla::get<0, 1>(dstTensor.stride()); | ||
| 255 | + auto srcCoord = srcTensor.coord(); | ||
| 256 | + | ||
| 257 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 258 | + loadDataParams.mStartPosition = CeilDiv<C0_NUM_PER_FRACTAL>(tla::get<1>(srcCoord)); | ||
| 259 | + loadDataParams.kStartPosition = CeilDiv<ELE_NUM_PER_C0>(tla::get<0>(srcCoord)); | ||
| 260 | + loadDataParams.mStep = dstOuterShapeCol; | ||
| 261 | + loadDataParams.kStep = dstOuterShapeRow; | ||
| 262 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideRow); | ||
| 263 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideRow); | ||
| 264 | + loadDataParams.ifTranspose = false; | ||
| 265 | + | ||
| 266 | + auto dstOffset = dstTensor.layout()(dstTensor.coord()); | ||
| 267 | + AscendC::LoadData(dstTensor.data()[dstOffset], srcTensor.data(), loadDataParams); | ||
| 268 | + } | ||
| 269 | + | ||
| 270 | + template <class TensorDst, class TensorSrc> | ||
| 271 | + __aicore__ inline void operator()(TensorDst const &dstTensor, TensorSrc const &srcTensor, uint32_t l0Batch) | ||
| 272 | + { | ||
| 273 | + static_assert( | ||
| 274 | + tla::detail::isnZ<typename TensorSrc::Element, typename TensorSrc::Layout>::value | ||
| 275 | + && tla::detail::isnZ<typename TensorDst::Element, typename TensorDst::Layout>::value | ||
| 276 | + && TensorSrc::position == AscendC::TPosition::A1 && TensorDst::position == AscendC::TPosition::B2, | ||
| 277 | + "The input parameters do not match. TensorSrc must be L1 and nZ, while TensorDst must be L0B and nZ" | ||
| 278 | + ); | ||
| 279 | + | ||
| 280 | + const uint32_t dstOuterShapeRow = tla::get<0, 1>(dstTensor.shape()); | ||
| 281 | + const uint32_t dstOuterShapeCol = tla::get<1, 1>(dstTensor.shape()); | ||
| 282 | + const uint32_t srcOuterStrideRow = tla::get<0, 1>(srcTensor.stride()); | ||
| 283 | + const uint32_t dstOuterStrideRow = tla::get<0, 1>(dstTensor.stride()); | ||
| 284 | + | ||
| 285 | + AscendC::LoadData2DParamsV2 loadDataParams; | ||
| 286 | + loadDataParams.mStartPosition = 0; | ||
| 287 | + loadDataParams.kStartPosition = 0; | ||
| 288 | + loadDataParams.mStep = dstOuterShapeCol; | ||
| 289 | + loadDataParams.kStep = dstOuterShapeRow * l0Batch; | ||
| 290 | + loadDataParams.srcStride = CeilDiv<ELE_NUM_PER_FRACTAL>(srcOuterStrideRow); | ||
| 291 | + loadDataParams.dstStride = CeilDiv<ELE_NUM_PER_FRACTAL>(dstOuterStrideRow); | ||
| 292 | + loadDataParams.ifTranspose = false; | ||
| 293 | + | ||
| 294 | + AscendC::LoadData(dstTensor.data(), srcTensor.data(), loadDataParams); | ||
| 295 | + } | ||
| 296 | +}; | ||
| 297 | + | ||
| 298 | +///////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 299 | + | ||
| 300 | +} // namespace NpuArch::Gemm::Tile | ||
| 301 | + | ||
| 302 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/gemm/tile_common/copy_ub_to_gm.hpp+21-0
| @@ -0,0 +1,21 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace NpuArch::Gemm::Tile { | ||
| 18 | + | ||
| 19 | +} // NpuArch::Gemm::Tile | ||
| 20 | + | ||
| 21 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/gemm/tile_common/tile_copy.hpp+203-0
| @@ -0,0 +1,203 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 36 | +namespace NpuArch::Gemm::Tile { | ||
| 37 | + | ||
| 38 | + | ||
| 39 | +template < | ||
| 40 | + /// Tag indicating architecture | ||
| 41 | + class ArchTag, | ||
| 42 | + /// GemmType for A matrix operand | ||
| 43 | + class AType, | ||
| 44 | + /// GemmType type for B matrix operand | ||
| 45 | + class BType, | ||
| 46 | + /// GemmType type for C matrix operand | ||
| 47 | + class CType, | ||
| 48 | + /// GemmType type for Bias operand | ||
| 49 | + class BiasType = void | ||
| 50 | +> | ||
| 51 | +struct TileCopy { | ||
| 52 | + using ElementA = typename AType::Element; | ||
| 53 | + using ElementB = typename BType::Element; | ||
| 54 | + using ElementAccumulator = | ||
| 55 | + typename Gemm::helper::ElementAccumulatorSelector<ElementA, ElementB>::ElementAccumulator; | ||
| 56 | + | ||
| 57 | + using CopyGmToL1A = Gemm::Tile::CopyGmToL1<ArchTag, AType>; | ||
| 58 | + using CopyGmToL1B = Gemm::Tile::CopyGmToL1<ArchTag, BType>; | ||
| 59 | + using CopyL1ToL0A = Gemm::Tile::CopyL1ToL0A< | ||
| 60 | + ArchTag, typename helper::L1ATypeSelector<AType>::L1AType>; | ||
| 61 | + using CopyL1ToL0B = Gemm::Tile::CopyL1ToL0B< | ||
| 62 | + ArchTag, typename helper::L1BTypeSelector<BType>::L1BType>; | ||
| 63 | + using CopyL0CToGm = Gemm::Tile::CopyL0CToGm<ArchTag, ElementAccumulator, CType>; | ||
| 64 | + using BiasTypeSelector = helper::L1BiasTypeSelector<BiasType, ElementAccumulator>; | ||
| 65 | + using CopyGmToL1Bias = std::conditional_t<std::is_same_v<BiasType, void>, | ||
| 66 | + void, | ||
| 67 | + Gemm::Tile::CopyGmToL1<ArchTag, | ||
| 68 | + typename BiasTypeSelector::GMBiasType, | ||
| 69 | + typename BiasTypeSelector::L1BiasType>>; | ||
| 70 | +}; | ||
| 71 | + | ||
| 72 | + | ||
| 73 | +template < | ||
| 74 | + /// Tag indicating architecture | ||
| 75 | + class ArchTag, | ||
| 76 | + class ElementA_, | ||
| 77 | + class LayoutTagA_, | ||
| 78 | + class ElementB_, | ||
| 79 | + class LayoutTagB_, | ||
| 80 | + class ElementC_, | ||
| 81 | + class LayoutTagC_, | ||
| 82 | + class ElementBias = void, | ||
| 83 | + bool ReluEnable_ = false, | ||
| 84 | + ScaleGranularity DEQUANT_GRANULARITY = ScaleGranularity::NO_QUANT, | ||
| 85 | + class L0CCopyMode = CopyToGM | ||
| 86 | +> | ||
| 87 | +struct PackedTileCopyTla { | ||
| 88 | + using ElementA = ElementA_; | ||
| 89 | + using ElementB = ElementB_; | ||
| 90 | + using LayoutTagA = LayoutTagA_; | ||
| 91 | + using LayoutTagB = LayoutTagB_; | ||
| 92 | + using LayoutTagC = LayoutTagC_; | ||
| 93 | + using ElementAccumulator = | ||
| 94 | + typename Gemm::helper::ElementAccumulatorSelector<ElementA, ElementB>::ElementAccumulator; | ||
| 95 | + static constexpr bool ReluEnable = ReluEnable_; | ||
| 96 | + | ||
| 97 | + static constexpr bool HAS_BIAS = !std::is_void_v<ElementBias>; | ||
| 98 | + | ||
| 99 | + using LayoutTagL1A = typename helper::L1ATypeSelector<Gemm::GemmType<ElementA, LayoutTagA>>::L1AType::Layout; | ||
| 100 | + using LayoutTagL1B = typename helper::L1BTypeSelector<Gemm::GemmType<ElementB, LayoutTagB>>::L1BType::Layout; | ||
| 101 | + using LayoutTagL0A = typename helper::L0ALayoutSelector<ArchTag>::Layout; | ||
| 102 | + using LayoutTagL0B = layout::nZ; | ||
| 103 | + | ||
| 104 | + using LayoutA = detail::TagToLayout_t<ElementA, LayoutTagA>; | ||
| 105 | + using LayoutB = detail::TagToLayout_t<ElementB, LayoutTagB>; | ||
| 106 | + using LayoutC = detail::TagToLayout_t<ElementC_, LayoutTagC>; | ||
| 107 | + | ||
| 108 | + using LayoutL1A = detail::TagToLayout_t<ElementA, LayoutTagL1A>; | ||
| 109 | + using LayoutL1B = detail::TagToLayout_t<ElementB, LayoutTagL1B>; | ||
| 110 | + using LayoutL0A = detail::TagToLayout_t<ElementA, LayoutTagL0A>; | ||
| 111 | + using LayoutL0B = detail::TagToLayout_t<ElementB, LayoutTagL0B>; | ||
| 112 | + using LayoutL0C = typename detail::LayoutL0C; | ||
| 113 | + | ||
| 114 | + using TensorL1AVectorLayout = | ||
| 115 | + tla::Tensor<AscendC::LocalTensor<ElementA>, LayoutL1A, tla::Coord<tla::_0>, AscendC::TPosition::A1>; | ||
| 116 | + using TensorL1ALayout = | ||
| 117 | + tla::Tensor<AscendC::LocalTensor<ElementA>, LayoutL1A, tla::Coord<tla::_0, tla::_0>, AscendC::TPosition::A1>; | ||
| 118 | + | ||
| 119 | + using TensorL1A = std::conditional_t<tla::detail::isVector<LayoutTagA>::value, TensorL1AVectorLayout, TensorL1ALayout>; | ||
| 120 | + using TensorL1B = | ||
| 121 | + tla::Tensor<AscendC::LocalTensor<ElementB>, LayoutL1B, tla::Coord<tla::_0, tla::_0>, AscendC::TPosition::A1>; | ||
| 122 | + using TensorL0A = | ||
| 123 | + tla::Tensor<AscendC::LocalTensor<ElementA>, LayoutL0A, tla::Coord<tla::_0, tla::_0>, AscendC::TPosition::A2>; | ||
| 124 | + using TensorL0B = | ||
| 125 | + tla::Tensor<AscendC::LocalTensor<ElementB>, LayoutL0B, tla::Coord<tla::_0, tla::_0>, AscendC::TPosition::B2>; | ||
| 126 | + using TensorL0C = tla::Tensor<AscendC::LocalTensor<ElementAccumulator>, LayoutL0C, tla::Coord<tla::_0, tla::_0>, | ||
| 127 | + AscendC::TPosition::CO1>; | ||
| 128 | + using TensorL1Bias = std::conditional_t< | ||
| 129 | + HAS_BIAS, | ||
| 130 | + tla::Tensor<AscendC::LocalTensor<ElementBias>, detail::TagToLayout_t<ElementBias, layout::VectorLayout>, | ||
| 131 | + tla::Coord<tla::_0>, AscendC::TPosition::A1>, | ||
| 132 | + EmptyClass>; | ||
| 133 | + using TensorL0Bias = tla::Tensor< | ||
| 134 | + AscendC::LocalTensor<ElementAccumulator>, | ||
| 135 | + detail::TagToLayout_t<ElementAccumulator, layout::VectorLayout>, | ||
| 136 | + tla::Coord<tla::_0>, | ||
| 137 | + AscendC::TPosition::C2>; | ||
| 138 | + | ||
| 139 | + using L1AAlignHelper = Gemm::helper::L1AlignHelper<ElementA, LayoutTagA>; | ||
| 140 | + using L1BAlignHelper = Gemm::helper::L1AlignHelper<ElementB, LayoutTagB>; | ||
| 141 | + | ||
| 142 | + template <class TensorA> | ||
| 143 | + using CopyGmToL1A = Gemm::Tile::TileCopyTla<ArchTag, TensorA, TensorL1A>; | ||
| 144 | + | ||
| 145 | + template <class TensorB> | ||
| 146 | + using CopyGmToL1B = Gemm::Tile::TileCopyTla<ArchTag, TensorB, TensorL1B>; | ||
| 147 | + | ||
| 148 | + template <class TensorBias> | ||
| 149 | + using CopyGmToL1Bias = std::conditional_t< | ||
| 150 | + HAS_BIAS, | ||
| 151 | + Gemm::Tile::TileCopyTla<ArchTag, TensorBias, TensorL1Bias>, | ||
| 152 | + EmptyClass>; | ||
| 153 | + | ||
| 154 | + using CopyL1ToL0A = Gemm::Tile::TileCopyTla<ArchTag, TensorL1A, TensorL0A>; | ||
| 155 | + using CopyL1ToL0B = Gemm::Tile::TileCopyTla<ArchTag, TensorL1B, TensorL0B>; | ||
| 156 | + using CopyL1ToBT = std::conditional_t< | ||
| 157 | + HAS_BIAS, | ||
| 158 | + Gemm::Tile::TileCopyTla<ArchTag, TensorL1Bias, TensorL0Bias>, | ||
| 159 | + EmptyClass>; | ||
| 160 | + | ||
| 161 | + template <class TensorC> | ||
| 162 | + using CopyL0CToDst = Gemm::Tile::CopyL0CToGmTla<ArchTag, TensorL0C, TensorC, DEQUANT_GRANULARITY, ReluEnable>; | ||
| 163 | +}; | ||
| 164 | + | ||
| 165 | + | ||
| 166 | +template < | ||
| 167 | + /// Tag indicating architecture | ||
| 168 | + class ArchTag, | ||
| 169 | + class ElementA_, | ||
| 170 | + class LayoutTagA, | ||
| 171 | + class ElementB_, | ||
| 172 | + class LayoutTagB, | ||
| 173 | + class ElementC_, | ||
| 174 | + class LayoutTagC, | ||
| 175 | + class ElementBias = void, | ||
| 176 | + CopyL0CToUBMode CopyMode_ = CopyL0CToUBMode::NO_SPLIT, | ||
| 177 | + bool ReluEnable = false, | ||
| 178 | + ScaleGranularity DEQUANT_GRANULARITY = ScaleGranularity::NO_QUANT | ||
| 179 | +> | ||
| 180 | +struct PackedTileCopyTlaToUB : public PackedTileCopyTla<ArchTag, ElementA_, LayoutTagA, ElementB_, LayoutTagB, | ||
| 181 | + ElementC_, LayoutTagC, ElementBias> { | ||
| 182 | + static constexpr CopyL0CToUBMode CopyMode = CopyMode_; | ||
| 183 | + // 重写 CopyL0CToDst | ||
| 184 | + using TensorL0C = typename PackedTileCopyTla< | ||
| 185 | + ArchTag, | ||
| 186 | + ElementA_, | ||
| 187 | + LayoutTagA, | ||
| 188 | + ElementB_, | ||
| 189 | + LayoutTagB, | ||
| 190 | + ElementC_, | ||
| 191 | + LayoutTagC, | ||
| 192 | + ElementBias>::TensorL0C; | ||
| 193 | + | ||
| 194 | + template <class TensorC> | ||
| 195 | + using CopyL0CToDst = | ||
| 196 | + Gemm::Tile::CopyL0CToUBTla<ArchTag, TensorL0C, TensorC, CopyMode, DEQUANT_GRANULARITY, ReluEnable>; | ||
| 197 | +}; | ||
| 198 | + | ||
| 199 | + | ||
| 200 | +////////////////////////////// | ||
| 201 | +} // namespace NpuArch::Gemm::Tile | ||
| 202 | + | ||
| 203 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/gemm/tile_common/tile_copy_tla.hpp+28-0
| @@ -0,0 +1,28 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace NpuArch::Gemm::Tile { | ||
| 17 | +template < | ||
| 18 | + class ArchTag, | ||
| 19 | + class TensorSrc, | ||
| 20 | + class TensorDst, | ||
| 21 | + class Enable = void | ||
| 22 | +> | ||
| 23 | +struct TileCopyTla { | ||
| 24 | + static_assert(DEPENDENT_FALSE<ArchTag>, "Unsupported TileCopyTla, can not find the specialization."); | ||
| 25 | +}; | ||
| 26 | +} // namespace NpuArch::Gemm::Tile | ||
| 27 | + | ||
| 28 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/attn_infra/gemm/tile_common/tile_mmad.hpp+227-0
| @@ -0,0 +1,227 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace NpuArch::Gemm::Tile { | ||
| 18 | + | ||
| 19 | +/////////////////////////////////////////////////////////// | ||
| 20 | + | ||
| 21 | +template < | ||
| 22 | + /// Tag indicating architecture | ||
| 23 | + class ArchTag_, | ||
| 24 | + /// GemmType for A matrix operand | ||
| 25 | + class AType_, | ||
| 26 | + /// GemmType type for B matrix operand | ||
| 27 | + class BType_, | ||
| 28 | + /// GemmType type for Bias operand | ||
| 29 | + class BiasType_ | ||
| 30 | +> | ||
| 31 | +struct TileMmad { | ||
| 32 | + using ElementA = typename AType_::Element; | ||
| 33 | + using ElementB = typename BType_::Element; | ||
| 34 | + using ElementAccumulator = | ||
| 35 | + typename Gemm::helper::ElementAccumulatorSelector<ElementA, ElementB>::ElementAccumulator; | ||
| 36 | + | ||
| 37 | + // Methods | ||
| 38 | + | ||
| 39 | + __aicore__ inline | ||
| 40 | + TileMmad() {} | ||
| 41 | + | ||
| 42 | + __aicore__ inline | ||
| 43 | + void operator()(AscendC::LocalTensor<ElementAccumulator> const &l0CTensor, | ||
| 44 | + AscendC::LocalTensor<ElementA> const &l0ATensor, | ||
| 45 | + AscendC::LocalTensor<ElementB> const &l0BTensor, | ||
| 46 | + uint32_t m, uint32_t n, uint32_t k, | ||
| 47 | + bool initC = true, uint8_t unitFlag = 0) | ||
| 48 | + { | ||
| 49 | + AscendC::MmadParams mmadParams; | ||
| 50 | + mmadParams.m = m; | ||
| 51 | + mmadParams.n = n; | ||
| 52 | + mmadParams.k = k; | ||
| 53 | + mmadParams.unitFlag = unitFlag; | ||
| 54 | + mmadParams.cmatrixInitVal = initC; | ||
| 55 | + if constexpr (std::is_same_v<ElementA, float> && std::is_same_v<typename AType_::Layout, layout::ColumnMajor>) { | ||
| 56 | + mmadParams.kDirectionAlign = true; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + AscendC::Mmad(l0CTensor, | ||
| 60 | + l0ATensor, | ||
| 61 | + l0BTensor, | ||
| 62 | + mmadParams); | ||
| 63 | + | ||
| 64 | + const uint32_t PIPE_M_BARRIER_THRESHOLD = 10; | ||
| 65 | + if ((m / C0_NUM_PER_FRACTAL) * (n / C0_NUM_PER_FRACTAL) < PIPE_M_BARRIER_THRESHOLD) { | ||
| 66 | + AscendC::PipeBarrier<PIPE_M>(); | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + __aicore__ inline | ||
| 71 | + void operator()(AscendC::LocalTensor<ElementAccumulator> const &l0CTensor, | ||
| 72 | + AscendC::LocalTensor<ElementA> const &l0ATensor, | ||
| 73 | + AscendC::LocalTensor<ElementB> const &l0BTensor, | ||
| 74 | + AscendC::LocalTensor<ElementAccumulator> const &l0BiasTensor, | ||
| 75 | + uint32_t m, uint32_t n, uint32_t k, | ||
| 76 | + bool initC = true, uint8_t unitFlag = 0) | ||
| 77 | + { | ||
| 78 | + AscendC::MmadParams mmadParams; | ||
| 79 | + mmadParams.m = m; | ||
| 80 | + mmadParams.n = n; | ||
| 81 | + mmadParams.k = k; | ||
| 82 | + mmadParams.unitFlag = unitFlag; | ||
| 83 | + mmadParams.cmatrixInitVal = false; | ||
| 84 | + if constexpr (std::is_same_v<ElementA, float> && std::is_same_v<typename AType_::Layout, layout::ColumnMajor>) { | ||
| 85 | + mmadParams.kDirectionAlign = true; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + AscendC::Mmad(l0CTensor, | ||
| 89 | + l0ATensor, | ||
| 90 | + l0BTensor, | ||
| 91 | + l0BiasTensor, | ||
| 92 | + mmadParams); | ||
| 93 | + | ||
| 94 | + const uint32_t PIPE_M_BARRIER_THRESHOLD = 10; | ||
| 95 | + if ((m / C0_NUM_PER_FRACTAL) * (n / C0_NUM_PER_FRACTAL) < PIPE_M_BARRIER_THRESHOLD) { | ||
| 96 | + AscendC::PipeBarrier<PIPE_M>(); | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | +}; | ||
| 100 | + | ||
| 101 | +template < | ||
| 102 | + /// Tag indicating architecture | ||
| 103 | + class ArchTag, | ||
| 104 | + /// Element for A matrix operand | ||
| 105 | + class ElementA, | ||
| 106 | + /// LayoutTag for A matrix operand in L1 | ||
| 107 | + class LayoutTagL1A | ||
| 108 | +> | ||
| 109 | +struct TileMmadTla { | ||
| 110 | + // Methods | ||
| 111 | + | ||
| 112 | + __aicore__ inline | ||
| 113 | + TileMmadTla() {} | ||
| 114 | + | ||
| 115 | + template <class TensorC, class TensorA, class TensorB> | ||
| 116 | + __aicore__ inline | ||
| 117 | + void operator()(TensorC const &l0CTensor, | ||
| 118 | + TensorA const &l0ATensor, | ||
| 119 | + TensorB const &l0BTensor, | ||
| 120 | + uint32_t m, uint32_t n, uint32_t k, | ||
| 121 | + bool initC = true, uint8_t unitFlag = 0) | ||
| 122 | + { | ||
| 123 | + AscendC::MmadParams mmadParams; | ||
| 124 | + mmadParams.m = m; | ||
| 125 | + mmadParams.n = n; | ||
| 126 | + mmadParams.k = k; | ||
| 127 | + mmadParams.unitFlag = unitFlag; | ||
| 128 | + mmadParams.cmatrixInitVal = initC; | ||
| 129 | + | ||
| 130 | + if constexpr(std::is_same_v<LayoutTagL1A, layout::VectorLayout>) { | ||
| 131 | + mmadParams.disableGemv = false; | ||
| 132 | + } else { | ||
| 133 | + mmadParams.disableGemv = true; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + | ||
| 137 | + if constexpr (std::is_same_v<ElementA, float> && std::is_same_v<LayoutTagL1A, layout::nZ>) { | ||
| 138 | + mmadParams.kDirectionAlign = true; | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + | ||
| 142 | + AscendC::Mmad(l0CTensor.data(), | ||
| 143 | + l0ATensor.data(), | ||
| 144 | + l0BTensor.data(), | ||
| 145 | + mmadParams); | ||
| 146 | + | ||
| 147 | + const uint32_t PIPE_M_BARRIER_THRESHOLD = 10; | ||
| 148 | + if ((m / C0_NUM_PER_FRACTAL) * (n / C0_NUM_PER_FRACTAL) < PIPE_M_BARRIER_THRESHOLD) { | ||
| 149 | + AscendC::PipeBarrier<PIPE_M>(); | ||
| 150 | + } | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + template <class TensorC, class TensorA, class TensorB, class TensorBias> | ||
| 154 | + __aicore__ inline | ||
| 155 | + void operator()(TensorC const &l0CTensor, | ||
| 156 | + TensorA const &l0ATensor, | ||
| 157 | + TensorB const &l0BTensor, | ||
| 158 | + TensorBias const &l0BiasTensor, | ||
| 159 | + uint32_t m, uint32_t n, uint32_t k, | ||
| 160 | + bool initC = true, uint8_t unitFlag = 0) | ||
| 161 | + { | ||
| 162 | + AscendC::MmadParams mmadParams; | ||
| 163 | + mmadParams.m = m; | ||
| 164 | + mmadParams.n = n; | ||
| 165 | + mmadParams.k = k; | ||
| 166 | + mmadParams.unitFlag = unitFlag; | ||
| 167 | + mmadParams.cmatrixInitVal = false; | ||
| 168 | + | ||
| 169 | + mmadParams.disableGemv = true; | ||
| 170 | + | ||
| 171 | + | ||
| 172 | + if constexpr (std::is_same_v<ElementA, float> && std::is_same_v<LayoutTagL1A, layout::nZ>) { | ||
| 173 | + mmadParams.kDirectionAlign = true; | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + | ||
| 177 | + AscendC::Mmad(l0CTensor.data(), | ||
| 178 | + l0ATensor.data(), | ||
| 179 | + l0BTensor.data(), | ||
| 180 | + l0BiasTensor.data(), | ||
| 181 | + mmadParams); | ||
| 182 | + | ||
| 183 | + const uint32_t PIPE_M_BARRIER_THRESHOLD = 10; | ||
| 184 | + if ((m / C0_NUM_PER_FRACTAL) * (n / C0_NUM_PER_FRACTAL) < PIPE_M_BARRIER_THRESHOLD) { | ||
| 185 | + AscendC::PipeBarrier<PIPE_M>(); | ||
| 186 | + } | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + template <class TensorC, class TensorA, class TensorB> | ||
| 190 | + __aicore__ inline | ||
| 191 | + void operator()(TensorC const &l0CTensor, | ||
| 192 | + TensorA const &l0ATensor, | ||
| 193 | + TensorB const &l0BTensor, | ||
| 194 | + uint32_t m, uint32_t n, uint32_t k, | ||
| 195 | + uint32_t l0Batch) | ||
| 196 | + { | ||
| 197 | + const uint32_t L0AM = tla::get<0, 0>(l0ATensor.shape()) * tla::get<0, 1>(l0ATensor.shape()); | ||
| 198 | + const uint32_t L0AK = tla::get<1, 0>(l0ATensor.shape()) * tla::get<1, 1>(l0ATensor.shape()); | ||
| 199 | + const uint32_t L0BK = tla::get<0, 0>(l0BTensor.shape()) * tla::get<0, 1>(l0BTensor.shape()); | ||
| 200 | + const uint32_t L0BN = tla::get<1, 0>(l0BTensor.shape()) * tla::get<1, 1>(l0BTensor.shape()); | ||
| 201 | + const uint32_t L0CM = tla::get<0, 0>(l0CTensor.shape()) * tla::get<0, 1>(l0CTensor.shape()); | ||
| 202 | + const uint32_t L0CN = tla::get<1, 0>(l0CTensor.shape()) * tla::get<1, 1>(l0CTensor.shape()); | ||
| 203 | + | ||
| 204 | + AscendC::MmadParams mmadParams; | ||
| 205 | + mmadParams.m = m; | ||
| 206 | + mmadParams.n = n; | ||
| 207 | + mmadParams.k = k; | ||
| 208 | + mmadParams.unitFlag = 0; | ||
| 209 | + mmadParams.cmatrixInitVal = true; | ||
| 210 | + | ||
| 211 | + mmadParams.disableGemv = true; | ||
| 212 | + | ||
| 213 | + | ||
| 214 | + for (uint32_t l0BatchIdx = 0; l0BatchIdx < l0Batch; l0BatchIdx++) { | ||
| 215 | + AscendC::Mmad(l0CTensor.data()[l0BatchIdx * L0CM * L0CN], | ||
| 216 | + l0ATensor.data()[l0BatchIdx * L0AM * L0AK], | ||
| 217 | + l0BTensor.data()[l0BatchIdx * L0BK * L0BN], | ||
| 218 | + mmadParams); | ||
| 219 | + } | ||
| 220 | + } | ||
| 221 | +}; | ||
| 222 | + | ||
| 223 | +///////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 224 | + | ||
| 225 | +} // namespace NpuArch::Gemm::Tile | ||
| 226 | + | ||
| 227 | + | ||
| @@ -0,0 +1,163 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file gemm_coord.hpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace NpuArch { | ||
| 22 | + | ||
| 23 | +/// Shape of a matrix multiply-add operation | ||
| 24 | +template < | ||
| 25 | + /// Rows of matrix product | ||
| 26 | + uint32_t M_ = 1, | ||
| 27 | + /// Columns of matrix product | ||
| 28 | + uint32_t N_ = 1, | ||
| 29 | + /// Inner dimension of matrix product | ||
| 30 | + uint32_t K_ = 1 | ||
| 31 | +> | ||
| 32 | +struct GemmShape { | ||
| 33 | + static constexpr uint32_t M = M_; | ||
| 34 | + static constexpr uint32_t N = N_; | ||
| 35 | + static constexpr uint32_t K = K_; | ||
| 36 | + | ||
| 37 | + static constexpr int64_t MN = M * N; | ||
| 38 | + static constexpr int64_t MK = M * K; | ||
| 39 | + static constexpr int64_t KN = N * K; | ||
| 40 | + static constexpr int64_t MNK = M * N * K; | ||
| 41 | + | ||
| 42 | + static constexpr int64_t COUNT = MNK; | ||
| 43 | + | ||
| 44 | + /// Returns a Coord object | ||
| 45 | + HOST_DEVICE | ||
| 46 | + static Coord<3> ToCoord() | ||
| 47 | + { | ||
| 48 | + return MakeCoord(M, N, K); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + HOST_DEVICE | ||
| 52 | + static Coord<2> ToCoordMN() | ||
| 53 | + { | ||
| 54 | + return MakeCoord(M, N); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + HOST_DEVICE | ||
| 58 | + static Coord<2> ToCoordMK() | ||
| 59 | + { | ||
| 60 | + return MakeCoord(M, K); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + HOST_DEVICE | ||
| 64 | + static Coord<2> ToCoordKN() | ||
| 65 | + { | ||
| 66 | + return MakeCoord(K, N); | ||
| 67 | + } | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +/// GemmCoord is a structure derived from Coord<3> that specifies a location within the | ||
| 71 | +/// coordinate space of a Gemm problem. | ||
| 72 | +struct GemmCoord : public Coord<3, uint32_t> { | ||
| 73 | + /// Integer-valued index | ||
| 74 | + using Index = uint32_t; | ||
| 75 | + | ||
| 76 | + /// Base type is a Coord of rank=3 | ||
| 77 | + using Base = Coord<3, Index>; | ||
| 78 | + | ||
| 79 | + /// Gemm M dimension - rows of the output C matrix | ||
| 80 | + static constexpr int M_INDEX = 0; | ||
| 81 | + | ||
| 82 | + /// Gemm N dimension - columns of the output C matrix | ||
| 83 | + static constexpr int N_INDEX = 1; | ||
| 84 | + | ||
| 85 | + /// Gemm K dimension - inner dimension of the Gemm problem | ||
| 86 | + static constexpr int K_INDEX = 2; | ||
| 87 | + | ||
| 88 | + /// Default ctor | ||
| 89 | + HOST_DEVICE | ||
| 90 | + GemmCoord() {} | ||
| 91 | + | ||
| 92 | + /// Constructs from Coord<3> and a batch | ||
| 93 | + HOST_DEVICE | ||
| 94 | + GemmCoord(Coord<3, Index> const &coord) : Base(coord) {} | ||
| 95 | + | ||
| 96 | + /// Helper to construct from a K, N, M, batch variables | ||
| 97 | + HOST_DEVICE | ||
| 98 | + GemmCoord(Index m, Index n, Index k) : Base(MakeCoord(m, n, k)) {} | ||
| 99 | + | ||
| 100 | + /// Returns the Gemm M coordinate | ||
| 101 | + HOST_DEVICE | ||
| 102 | + Index const &m() const | ||
| 103 | + { | ||
| 104 | + return this->At(M_INDEX); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + /// Returns reference to the Gemm M coordinate | ||
| 108 | + HOST_DEVICE | ||
| 109 | + Index &m() | ||
| 110 | + { | ||
| 111 | + return this->At(M_INDEX); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /// Returns the Gemm N coordinate | ||
| 115 | + HOST_DEVICE | ||
| 116 | + Index const &n() const | ||
| 117 | + { | ||
| 118 | + return this->At(N_INDEX); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + /// Returns reference to the Gemm N coordinate | ||
| 122 | + HOST_DEVICE | ||
| 123 | + Index &n() | ||
| 124 | + { | ||
| 125 | + return this->At(N_INDEX); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + /// Returns the Gemm K coordinate | ||
| 129 | + HOST_DEVICE | ||
| 130 | + Index const &k() const | ||
| 131 | + { | ||
| 132 | + return this->At(K_INDEX); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + /// Returns reference to the Gemm K coordinate | ||
| 136 | + HOST_DEVICE | ||
| 137 | + Index &k() | ||
| 138 | + { | ||
| 139 | + return this->At(K_INDEX); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + HOST_DEVICE | ||
| 143 | + auto GetCoordMN() const | ||
| 144 | + { | ||
| 145 | + return this->GetCoordByAxis<M_INDEX, N_INDEX>(); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + HOST_DEVICE | ||
| 149 | + auto GetCoordMK() const | ||
| 150 | + { | ||
| 151 | + return this->GetCoordByAxis<M_INDEX, K_INDEX>(); | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + HOST_DEVICE | ||
| 155 | + auto GetCoordKN() const | ||
| 156 | + { | ||
| 157 | + return this->GetCoordByAxis<K_INDEX, N_INDEX>(); | ||
| 158 | + } | ||
| 159 | +}; | ||
| 160 | + | ||
| 161 | +} // namespace NpuArch | ||
| 162 | + | ||
| 163 | + | ||
| @@ -0,0 +1,18 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| @@ -0,0 +1,1247 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace NpuArch::layout | ||
| 20 | +{ | ||
| 21 | + | ||
| 22 | +/// Mapping function for row-major matrices | ||
| 23 | +struct RowMajor { | ||
| 24 | +public: | ||
| 25 | + /// Logical rank of tensor | ||
| 26 | + static constexpr int RANK = 2; | ||
| 27 | + | ||
| 28 | + /// Index type used for coordinates | ||
| 29 | + using Index = uint32_t; | ||
| 30 | + | ||
| 31 | + /// Long index type used for offsets | ||
| 32 | + using LongIndex = int64_t; | ||
| 33 | + | ||
| 34 | + /// Logical coordinate | ||
| 35 | + using Shape = Coord<RANK, Index>; | ||
| 36 | + | ||
| 37 | + /// Stride vector | ||
| 38 | + using Stride = Coord<RANK, LongIndex>; | ||
| 39 | + | ||
| 40 | +public: | ||
| 41 | + /// Constructor | ||
| 42 | + HOST_DEVICE | ||
| 43 | + RowMajor(Index rows = 0, Index cols = 0) | ||
| 44 | + : shape_(MakeCoord(rows, cols)), stride_(MakeCoord(LongIndex(cols), LongIndex(1))) {} | ||
| 45 | + | ||
| 46 | + /// Constructor | ||
| 47 | + HOST_DEVICE | ||
| 48 | + RowMajor(Index rows, Index cols, LongIndex ldm) | ||
| 49 | + : shape_(MakeCoord(rows, cols)), stride_(MakeCoord(ldm, LongIndex(1))) {} | ||
| 50 | + | ||
| 51 | + /// Ctor | ||
| 52 | + HOST_DEVICE | ||
| 53 | + RowMajor(Shape shape, Stride stride) : shape_(shape), stride_(stride) {} | ||
| 54 | + | ||
| 55 | + template <class Element> | ||
| 56 | + HOST_DEVICE | ||
| 57 | + static RowMajor MakeLayout(Index rows, Index cols) | ||
| 58 | + { | ||
| 59 | + return RowMajor(rows, cols); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + template <class Element> | ||
| 63 | + HOST_DEVICE | ||
| 64 | + static RowMajor MakeLayoutInUb(MatrixCoord const &shape) | ||
| 65 | + { | ||
| 66 | + return RowMajor(shape.row(), shape.column(), RoundUp<BYTE_PER_C0 / sizeof(Element)>(shape.column())); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /// Returns the offset of a coordinate in linear memory. | ||
| 70 | + /// Assumes coordinate has convention (row, column) | ||
| 71 | + HOST_DEVICE | ||
| 72 | + LongIndex GetOffset(MatrixCoord const &coord) const | ||
| 73 | + { | ||
| 74 | + return LongIndex(coord.row()) * stride_[0] + LongIndex(coord.column()); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + /// Returns the layout of a tile_common. | ||
| 78 | + HOST_DEVICE | ||
| 79 | + RowMajor GetTileLayout(MatrixCoord const &tileShape) const | ||
| 80 | + { | ||
| 81 | + return RowMajor(tileShape, stride()); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + /// Returns the shape of the layout | ||
| 85 | + HOST_DEVICE | ||
| 86 | + Shape shape() const | ||
| 87 | + { | ||
| 88 | + return shape_; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + /// Returns the shape of the layout | ||
| 92 | + HOST_DEVICE | ||
| 93 | + Shape &shape() | ||
| 94 | + { | ||
| 95 | + return shape_; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + /// Returns the shape of the layout | ||
| 99 | + HOST_DEVICE | ||
| 100 | + typename Shape::Index shape(int idx) const | ||
| 101 | + { | ||
| 102 | + return shape_[idx]; | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + /// Returns the shape of the layout | ||
| 106 | + HOST_DEVICE | ||
| 107 | + typename Shape::Index &shape(int idx) | ||
| 108 | + { | ||
| 109 | + return shape_[idx]; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + /// Returns the stride of the layout | ||
| 113 | + HOST_DEVICE | ||
| 114 | + Stride stride() const | ||
| 115 | + { | ||
| 116 | + return stride_; | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + /// Returns the stride of the layout | ||
| 120 | + HOST_DEVICE | ||
| 121 | + Stride &stride() | ||
| 122 | + { | ||
| 123 | + return stride_; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + /// Returns the stride of the layout | ||
| 127 | + HOST_DEVICE | ||
| 128 | + typename Stride::Index stride(int idx) const | ||
| 129 | + { | ||
| 130 | + return stride_[idx]; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + /// Returns the stride of the layout | ||
| 134 | + HOST_DEVICE | ||
| 135 | + typename Stride::Index &stride(int idx) | ||
| 136 | + { | ||
| 137 | + return stride_[idx]; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + /// Returns the length of the layout | ||
| 141 | + HOST_DEVICE | ||
| 142 | + LongIndex Capacity() const | ||
| 143 | + { | ||
| 144 | + return static_cast<LongIndex>(shape_[0]) * stride_[0]; | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | +protected: | ||
| 148 | + // | ||
| 149 | + // Data members | ||
| 150 | + // | ||
| 151 | + | ||
| 152 | + /// Shape data member | ||
| 153 | + Shape shape_; | ||
| 154 | + | ||
| 155 | + /// Stride data member | ||
| 156 | + Stride stride_; | ||
| 157 | +}; | ||
| 158 | + | ||
| 159 | +/// Mapping function for col-major matrices | ||
| 160 | +struct ColumnMajor { | ||
| 161 | +public: | ||
| 162 | + /// Logical rank of tensor | ||
| 163 | + static constexpr int RANK = 2; | ||
| 164 | + | ||
| 165 | + /// Index type used for coordinates | ||
| 166 | + using Index = uint32_t; | ||
| 167 | + | ||
| 168 | + /// Long index type used for offsets | ||
| 169 | + using LongIndex = int64_t; | ||
| 170 | + | ||
| 171 | + /// Logical coordinate | ||
| 172 | + using Shape = Coord<RANK, Index>; | ||
| 173 | + | ||
| 174 | + /// Stride vector | ||
| 175 | + using Stride = Coord<RANK, LongIndex>; | ||
| 176 | + | ||
| 177 | +public: | ||
| 178 | + // Methods | ||
| 179 | + | ||
| 180 | + /// Constructor | ||
| 181 | + HOST_DEVICE | ||
| 182 | + ColumnMajor(Index rows = 0, Index cols = 0) | ||
| 183 | + : shape_(MakeCoord(rows, cols)), stride_(MakeCoord(LongIndex(1), LongIndex(rows))) {} | ||
| 184 | + | ||
| 185 | + /// Constructor | ||
| 186 | + HOST_DEVICE | ||
| 187 | + ColumnMajor(Index rows, Index cols, LongIndex ldm) | ||
| 188 | + : shape_(MakeCoord(rows, cols)), stride_(MakeCoord(LongIndex(1), ldm)) {} | ||
| 189 | + | ||
| 190 | + /// Ctor | ||
| 191 | + HOST_DEVICE | ||
| 192 | + ColumnMajor(Shape shape, Stride stride) : shape_(shape), stride_(stride) {} | ||
| 193 | + | ||
| 194 | + template <class Element> | ||
| 195 | + HOST_DEVICE | ||
| 196 | + static ColumnMajor MakeLayout(Index rows, Index cols) | ||
| 197 | + { | ||
| 198 | + return ColumnMajor(rows, cols); | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + /// Returns the offset of a coordinate in linear memory. | ||
| 202 | + /// Assumes coordinate has convention (row, column) | ||
| 203 | + HOST_DEVICE | ||
| 204 | + LongIndex GetOffset(MatrixCoord const &coord) const | ||
| 205 | + { | ||
| 206 | + return LongIndex(coord.row()) + LongIndex(coord.column()) * stride_[1]; | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + /// Returns the layout of a tile_common. | ||
| 210 | + HOST_DEVICE | ||
| 211 | + ColumnMajor GetTileLayout(MatrixCoord const &tileShape) const | ||
| 212 | + { | ||
| 213 | + return ColumnMajor(tileShape, stride()); | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + /// Returns the shape of the layout | ||
| 217 | + HOST_DEVICE | ||
| 218 | + Shape shape() const | ||
| 219 | + { | ||
| 220 | + return shape_; | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + /// Returns the shape of the layout | ||
| 224 | + HOST_DEVICE | ||
| 225 | + Shape &shape() | ||
| 226 | + { | ||
| 227 | + return shape_; | ||
| 228 | + } | ||
| 229 | + | ||
| 230 | + /// Returns the shape of the layout | ||
| 231 | + HOST_DEVICE | ||
| 232 | + typename Shape::Index shape(int idx) const | ||
| 233 | + { | ||
| 234 | + return shape_[idx]; | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + /// Returns the shape of the layout | ||
| 238 | + HOST_DEVICE | ||
| 239 | + typename Shape::Index &shape(int idx) | ||
| 240 | + { | ||
| 241 | + return shape_[idx]; | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + /// Returns the stride of the layout | ||
| 245 | + HOST_DEVICE | ||
| 246 | + Stride stride() const | ||
| 247 | + { | ||
| 248 | + return stride_; | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + /// Returns the stride of the layout | ||
| 252 | + HOST_DEVICE | ||
| 253 | + Stride &stride() | ||
| 254 | + { | ||
| 255 | + return stride_; | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + /// Returns the stride of the layout | ||
| 259 | + HOST_DEVICE | ||
| 260 | + typename Stride::Index stride(int idx) const | ||
| 261 | + { | ||
| 262 | + return stride_[idx]; | ||
| 263 | + } | ||
| 264 | + | ||
| 265 | + /// Returns the stride of the layout | ||
| 266 | + HOST_DEVICE | ||
| 267 | + typename Stride::Index &stride(int idx) | ||
| 268 | + { | ||
| 269 | + return stride_[idx]; | ||
| 270 | + } | ||
| 271 | + | ||
| 272 | + /// Returns the length of the layout | ||
| 273 | + HOST_DEVICE | ||
| 274 | + LongIndex Capacity() const | ||
| 275 | + { | ||
| 276 | + return static_cast<LongIndex>(shape_[1]) * stride_[1]; | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | +protected: | ||
| 280 | + // | ||
| 281 | + // Data members | ||
| 282 | + // | ||
| 283 | + | ||
| 284 | + /// Shape data member | ||
| 285 | + Shape shape_; | ||
| 286 | + | ||
| 287 | + /// Stride data member | ||
| 288 | + Stride stride_; | ||
| 289 | +}; | ||
| 290 | + | ||
| 291 | +/// Mapping function for nZ matrices which is col-major inside fractal and row-major between fractal | ||
| 292 | +struct nZ { | ||
| 293 | +public: | ||
| 294 | + /// Logical rank of tensor | ||
| 295 | + static constexpr int RANK = 4; | ||
| 296 | + | ||
| 297 | + /// Index type used for coordinates | ||
| 298 | + using Index = uint32_t; | ||
| 299 | + | ||
| 300 | + /// Long index type used for offsets | ||
| 301 | + using LongIndex = int64_t; | ||
| 302 | + | ||
| 303 | + /// Logical rank of orgshape | ||
| 304 | + static constexpr int ORG_SHAPE_RANK = 2; | ||
| 305 | + | ||
| 306 | + /// Logical coordinate | ||
| 307 | + using OrgShape = Coord<ORG_SHAPE_RANK, Index>; | ||
| 308 | + | ||
| 309 | + /// Logical coordinate | ||
| 310 | + using Shape = Coord<RANK, Index>; | ||
| 311 | + | ||
| 312 | + /// Stride vector | ||
| 313 | + using Stride = Coord<RANK, LongIndex>; | ||
| 314 | + | ||
| 315 | +public: | ||
| 316 | + // Methods | ||
| 317 | + | ||
| 318 | + /// Constructor | ||
| 319 | + HOST_DEVICE constexpr | ||
| 320 | + nZ(Index orgRows = 0, /// Number of rows of origin matrices | ||
| 321 | + Index orgCols = 0, /// Number of cols of origin matrices | ||
| 322 | + Index rowsInFractal = 0, /// Number of rows inside the fractal | ||
| 323 | + Index rowsByFractal = 0, /// number of rows by the fractal | ||
| 324 | + Index colsInFractal = 0, /// number of cols inside the fractal | ||
| 325 | + Index colsByFractal = 0, /// number of cols by the fractal | ||
| 326 | + LongIndex strideRowsInFractal = 0, /// number of elements between adjacent rows inside the fractal | ||
| 327 | + LongIndex strideRowsByFractal = 0, /// number of elements between adjacent fractal rows | ||
| 328 | + LongIndex strideColsInFractal = 0, /// number of elements between adjacent cols inside the fractal | ||
| 329 | + LongIndex strideColsByFractal = 0) /// number of elements between adjacent fractal cols | ||
| 330 | + : orgShape_(MakeCoord(orgRows, orgCols)), | ||
| 331 | + shape_(MakeCoord(rowsInFractal, rowsByFractal, colsInFractal, colsByFractal)), | ||
| 332 | + stride_(MakeCoord(strideRowsInFractal, strideRowsByFractal, strideColsInFractal, strideColsByFractal)) {} | ||
| 333 | + | ||
| 334 | + /// Ctor | ||
| 335 | + HOST_DEVICE constexpr | ||
| 336 | + nZ(OrgShape orgShape, Shape shape, Stride stride) : orgShape_(orgShape), shape_(shape), stride_(stride) {} | ||
| 337 | + | ||
| 338 | + /// Make the layout of a coordinate (row, column) | ||
| 339 | + template <class Element> | ||
| 340 | + HOST_DEVICE constexpr | ||
| 341 | + static nZ MakeLayout(Index orgRows, Index orgCols) | ||
| 342 | + { | ||
| 343 | + constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 344 | + constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 345 | + Index rowsRound = RoundUp<ELE_NUM_PER_C0>(orgRows); | ||
| 346 | + Index colsRound = RoundUp<C0_NUM_PER_FRACTAL>(orgCols); | ||
| 347 | + return nZ(orgRows, | ||
| 348 | + orgCols, | ||
| 349 | + ELE_NUM_PER_C0, | ||
| 350 | + rowsRound / ELE_NUM_PER_C0, | ||
| 351 | + C0_NUM_PER_FRACTAL, | ||
| 352 | + colsRound / C0_NUM_PER_FRACTAL, | ||
| 353 | + 1, | ||
| 354 | + colsRound * ELE_NUM_PER_C0, | ||
| 355 | + ELE_NUM_PER_C0, | ||
| 356 | + ELE_NUM_PER_FRACTAL); | ||
| 357 | + } | ||
| 358 | + | ||
| 359 | + /// Returns the offset of a coordinate in linear memory. | ||
| 360 | + /// Assumes coordinate has convention (row, column) | ||
| 361 | + HOST_DEVICE | ||
| 362 | + LongIndex GetOffset(MatrixCoord const &coord) const | ||
| 363 | + { | ||
| 364 | + return LongIndex(coord.row()) / shape_[0] * stride_[1] + LongIndex(coord.column()) / shape_[2] * stride_[3] + | ||
| 365 | + (LongIndex(coord.row()) % shape_[0]) * stride_[0] + (LongIndex(coord.column()) % shape_[2]) * stride_[2]; | ||
| 366 | + } | ||
| 367 | + | ||
| 368 | + /// Returns the layout of a tile_common. | ||
| 369 | + HOST_DEVICE | ||
| 370 | + nZ GetTileLayout(MatrixCoord const &tileOriShape) const | ||
| 371 | + { | ||
| 372 | + auto tileShape = MakeCoord( | ||
| 373 | + shape(0), CeilDiv(tileOriShape.row(), shape(0)), | ||
| 374 | + shape(2), CeilDiv(tileOriShape.column(), shape(2)) | ||
| 375 | + ); | ||
| 376 | + return nZ(tileOriShape, tileShape, stride()); | ||
| 377 | + } | ||
| 378 | + | ||
| 379 | + /// Returns the origin shape of the layout | ||
| 380 | + HOST_DEVICE | ||
| 381 | + typename OrgShape::Index orgShape(int idx) const | ||
| 382 | + { | ||
| 383 | + return orgShape_[idx]; | ||
| 384 | + } | ||
| 385 | + | ||
| 386 | + /// Returns the origin shape of the layout | ||
| 387 | + HOST_DEVICE | ||
| 388 | + typename OrgShape::Index &orgShape(int idx) | ||
| 389 | + { | ||
| 390 | + return orgShape_[idx]; | ||
| 391 | + } | ||
| 392 | + | ||
| 393 | + /// Returns the shape of the layout | ||
| 394 | + HOST_DEVICE | ||
| 395 | + Shape shape() const | ||
| 396 | + { | ||
| 397 | + return shape_; | ||
| 398 | + } | ||
| 399 | + | ||
| 400 | + /// Returns the shape of the layout | ||
| 401 | + HOST_DEVICE | ||
| 402 | + Shape &shape() | ||
| 403 | + { | ||
| 404 | + return shape_; | ||
| 405 | + } | ||
| 406 | + | ||
| 407 | + /// Returns the shape of the layout | ||
| 408 | + HOST_DEVICE | ||
| 409 | + typename Shape::Index shape(int idx) const | ||
| 410 | + { | ||
| 411 | + return shape_[idx]; | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + /// Returns the shape of the layout | ||
| 415 | + HOST_DEVICE | ||
| 416 | + typename Shape::Index &shape(int idx) | ||
| 417 | + { | ||
| 418 | + return shape_[idx]; | ||
| 419 | + } | ||
| 420 | + | ||
| 421 | + /// Returns the stride of the layout | ||
| 422 | + HOST_DEVICE | ||
| 423 | + Stride stride() const | ||
| 424 | + { | ||
| 425 | + return stride_; | ||
| 426 | + } | ||
| 427 | + | ||
| 428 | + /// Returns the stride of the layout | ||
| 429 | + HOST_DEVICE | ||
| 430 | + Stride &stride() | ||
| 431 | + { | ||
| 432 | + return stride_; | ||
| 433 | + } | ||
| 434 | + | ||
| 435 | + /// Returns the stride of the layout | ||
| 436 | + HOST_DEVICE | ||
| 437 | + typename Stride::Index stride(int idx) const | ||
| 438 | + { | ||
| 439 | + return stride_[idx]; | ||
| 440 | + } | ||
| 441 | + | ||
| 442 | + /// Returns the stride of the layout | ||
| 443 | + HOST_DEVICE | ||
| 444 | + typename Stride::Index &stride(int idx) | ||
| 445 | + { | ||
| 446 | + return stride_[idx]; | ||
| 447 | + } | ||
| 448 | + | ||
| 449 | + /// Returns the length of the layout | ||
| 450 | + HOST_DEVICE | ||
| 451 | + LongIndex Capacity() const | ||
| 452 | + { | ||
| 453 | + return static_cast<LongIndex>(stride_[1]) * shape_[1]; | ||
| 454 | + } | ||
| 455 | + | ||
| 456 | +private: | ||
| 457 | + /// Origin Shape data member | ||
| 458 | + OrgShape orgShape_; | ||
| 459 | + | ||
| 460 | + /// Shape data member | ||
| 461 | + Shape shape_; | ||
| 462 | + | ||
| 463 | + /// Stride data member | ||
| 464 | + Stride stride_; | ||
| 465 | +}; | ||
| 466 | + | ||
| 467 | +/// Mapping function for zN matrices which is row-major inside fractal and col-major between fractal | ||
| 468 | +struct zN { | ||
| 469 | +public: | ||
| 470 | + /// Logical rank of tensor | ||
| 471 | + static constexpr int RANK = 4; | ||
| 472 | + | ||
| 473 | + /// Index type used for coordinates | ||
| 474 | + using Index = uint32_t; | ||
| 475 | + | ||
| 476 | + /// Long index type used for offsets | ||
| 477 | + using LongIndex = int64_t; | ||
| 478 | + | ||
| 479 | + /// Logical rank of orgshape | ||
| 480 | + static constexpr int ORG_SHAPE_RANK = 2; | ||
| 481 | + | ||
| 482 | + /// Logical coordinate | ||
| 483 | + using OrgShape = Coord<ORG_SHAPE_RANK, Index>; | ||
| 484 | + | ||
| 485 | + /// Logical coordinate | ||
| 486 | + using Shape = Coord<RANK, Index>; | ||
| 487 | + | ||
| 488 | + /// Stride vector | ||
| 489 | + using Stride = Coord<RANK, LongIndex>; | ||
| 490 | + | ||
| 491 | +public: | ||
| 492 | + // Methods | ||
| 493 | + | ||
| 494 | + /// Constructor | ||
| 495 | + HOST_DEVICE constexpr | ||
| 496 | + zN(Index orgRows = 0, /// Number of rows of origin matrices | ||
| 497 | + Index orgCols = 0, /// Number of cols of origin matrices | ||
| 498 | + Index rowsInFractal = 0, /// Number of rows inside the fractal | ||
| 499 | + Index rowsByFractal = 0, /// number of rows by the fractal | ||
| 500 | + Index colsInFractal = 0, /// number of cols inside the fractal | ||
| 501 | + Index colsByFractal = 0, /// number of cols by the fractal | ||
| 502 | + LongIndex strideRowsInFractal = 0, /// number of elements between adjacent rows inside the fractal | ||
| 503 | + LongIndex strideRowsByFractal = 0, /// number of elements between adjacent fractal rows | ||
| 504 | + LongIndex strideColsInFractal = 0, /// number of elements between adjacent cols inside the fractal | ||
| 505 | + LongIndex strideColsByFractal = 0) /// number of elements between adjacent fractal cols | ||
| 506 | + : orgShape_(MakeCoord(orgRows, orgCols)), | ||
| 507 | + shape_(MakeCoord(rowsInFractal, rowsByFractal, colsInFractal, colsByFractal)), | ||
| 508 | + stride_(MakeCoord(strideRowsInFractal, strideRowsByFractal, strideColsInFractal, strideColsByFractal)) {} | ||
| 509 | + | ||
| 510 | + /// Ctor | ||
| 511 | + HOST_DEVICE constexpr | ||
| 512 | + zN(OrgShape orgShape, Shape shape, Stride stride) : orgShape_(orgShape), shape_(shape), stride_(stride) {} | ||
| 513 | + | ||
| 514 | + /// Make the layout of a coordinate (row, column) | ||
| 515 | + template <class Element> | ||
| 516 | + HOST_DEVICE constexpr | ||
| 517 | + static zN MakeLayout(Index orgRows, Index orgCols) | ||
| 518 | + { | ||
| 519 | + constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 520 | + constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 521 | + Index rowsRound = RoundUp<C0_NUM_PER_FRACTAL>(orgRows); | ||
| 522 | + Index colsRound = RoundUp<ELE_NUM_PER_C0>(orgCols); | ||
| 523 | + return zN(orgRows, | ||
| 524 | + orgCols, | ||
| 525 | + C0_NUM_PER_FRACTAL, | ||
| 526 | + rowsRound / C0_NUM_PER_FRACTAL, | ||
| 527 | + ELE_NUM_PER_C0, | ||
| 528 | + colsRound / ELE_NUM_PER_C0, | ||
| 529 | + ELE_NUM_PER_C0, | ||
| 530 | + ELE_NUM_PER_FRACTAL, | ||
| 531 | + 1, | ||
| 532 | + rowsRound * ELE_NUM_PER_C0); | ||
| 533 | + } | ||
| 534 | + | ||
| 535 | + HOST_DEVICE | ||
| 536 | + static zN MakeLayoutInL0C(MatrixCoord const &shape) | ||
| 537 | + { | ||
| 538 | + return zN(shape.row(), | ||
| 539 | + shape.column(), | ||
| 540 | + C0_NUM_PER_FRACTAL, | ||
| 541 | + CeilDiv<C0_NUM_PER_FRACTAL>(shape.row()), | ||
| 542 | + C0_NUM_PER_FRACTAL, | ||
| 543 | + CeilDiv<C0_NUM_PER_FRACTAL>(shape.column()), | ||
| 544 | + C0_NUM_PER_FRACTAL, | ||
| 545 | + C0_NUM_PER_FRACTAL * C0_NUM_PER_FRACTAL, | ||
| 546 | + 1, | ||
| 547 | + RoundUp<C0_NUM_PER_FRACTAL>(shape.row()) * C0_NUM_PER_FRACTAL); | ||
| 548 | + } | ||
| 549 | + | ||
| 550 | + /// Returns the offset of a coordinate in linear memory. | ||
| 551 | + /// Assumes coordinate has convention (row, column) | ||
| 552 | + HOST_DEVICE | ||
| 553 | + LongIndex GetOffset(MatrixCoord const &coord) const | ||
| 554 | + { | ||
| 555 | + return LongIndex(coord.row()) / shape_[0] * stride_[1] + LongIndex(coord.column()) / shape_[2] * stride_[3] + | ||
| 556 | + (LongIndex(coord.row()) % shape_[0]) * stride_[0] + (LongIndex(coord.column()) % shape_[2]) * stride_[2]; | ||
| 557 | + } | ||
| 558 | + | ||
| 559 | + /// Returns the layout of a tile_common. | ||
| 560 | + HOST_DEVICE | ||
| 561 | + zN GetTileLayout(MatrixCoord const &tileOriShape) const | ||
| 562 | + { | ||
| 563 | + auto tileShape = MakeCoord( | ||
| 564 | + shape(0), CeilDiv(tileOriShape.row(), shape(0)), | ||
| 565 | + shape(2), CeilDiv(tileOriShape.column(), shape(2)) | ||
| 566 | + ); | ||
| 567 | + return zN(tileOriShape, tileShape, stride()); | ||
| 568 | + } | ||
| 569 | + | ||
| 570 | + /// Returns the origin shape of the layout | ||
| 571 | + HOST_DEVICE | ||
| 572 | + typename OrgShape::Index orgShape(int idx) const | ||
| 573 | + { | ||
| 574 | + return orgShape_[idx]; | ||
| 575 | + } | ||
| 576 | + | ||
| 577 | + /// Returns the origin shape of the layout | ||
| 578 | + HOST_DEVICE | ||
| 579 | + typename OrgShape::Index &orgShape(int idx) | ||
| 580 | + { | ||
| 581 | + return orgShape_[idx]; | ||
| 582 | + } | ||
| 583 | + | ||
| 584 | + /// Returns the shape of the layout | ||
| 585 | + HOST_DEVICE | ||
| 586 | + Shape shape() const | ||
| 587 | + { | ||
| 588 | + return shape_; | ||
| 589 | + } | ||
| 590 | + | ||
| 591 | + /// Returns the shape of the layout | ||
| 592 | + HOST_DEVICE | ||
| 593 | + Shape &shape() | ||
| 594 | + { | ||
| 595 | + return shape_; | ||
| 596 | + } | ||
| 597 | + | ||
| 598 | + /// Returns the shape of the layout | ||
| 599 | + HOST_DEVICE | ||
| 600 | + typename Shape::Index shape(int idx) const | ||
| 601 | + { | ||
| 602 | + return shape_[idx]; | ||
| 603 | + } | ||
| 604 | + | ||
| 605 | + /// Returns the shape of the layout | ||
| 606 | + HOST_DEVICE | ||
| 607 | + typename Shape::Index &shape(int idx) | ||
| 608 | + { | ||
| 609 | + return shape_[idx]; | ||
| 610 | + } | ||
| 611 | + | ||
| 612 | + /// Returns the stride of the layout | ||
| 613 | + HOST_DEVICE | ||
| 614 | + Stride stride() const | ||
| 615 | + { | ||
| 616 | + return stride_; | ||
| 617 | + } | ||
| 618 | + | ||
| 619 | + /// Returns the stride of the layout | ||
| 620 | + HOST_DEVICE | ||
| 621 | + Stride &stride() | ||
| 622 | + { | ||
| 623 | + return stride_; | ||
| 624 | + } | ||
| 625 | + | ||
| 626 | + /// Returns the stride of the layout | ||
| 627 | + HOST_DEVICE | ||
| 628 | + typename Stride::Index stride(int idx) const | ||
| 629 | + { | ||
| 630 | + return stride_[idx]; | ||
| 631 | + } | ||
| 632 | + | ||
| 633 | + /// Returns the stride of the layout | ||
| 634 | + HOST_DEVICE | ||
| 635 | + typename Stride::Index &stride(int idx) | ||
| 636 | + { | ||
| 637 | + return stride_[idx]; | ||
| 638 | + } | ||
| 639 | + | ||
| 640 | + /// Returns the length of the layout | ||
| 641 | + HOST_DEVICE | ||
| 642 | + LongIndex Capacity() const | ||
| 643 | + { | ||
| 644 | + return static_cast<LongIndex>(stride_[3]) * shape_[3]; | ||
| 645 | + } | ||
| 646 | + | ||
| 647 | +private: | ||
| 648 | + /// Origin Shape data member | ||
| 649 | + OrgShape orgShape_; | ||
| 650 | + | ||
| 651 | + /// Shape data member | ||
| 652 | + Shape shape_; | ||
| 653 | + | ||
| 654 | + /// Stride data member | ||
| 655 | + Stride stride_; | ||
| 656 | +}; | ||
| 657 | + | ||
| 658 | +/// Mapping function for zN matrices which is row-major inside fractal and row-major between fractal | ||
| 659 | +struct zZ { | ||
| 660 | +public: | ||
| 661 | + /// Logical rank of tensor | ||
| 662 | + static constexpr int RANK = 4; | ||
| 663 | + | ||
| 664 | + /// Index type used for coordinates | ||
| 665 | + using Index = uint32_t; | ||
| 666 | + | ||
| 667 | + /// Long index type used for offsets | ||
| 668 | + using LongIndex = int64_t; | ||
| 669 | + | ||
| 670 | + /// Logical rank of orgshape | ||
| 671 | + static constexpr int ORG_SHAPE_RANK = 2; | ||
| 672 | + | ||
| 673 | + /// Logical coordinate | ||
| 674 | + using OrgShape = Coord<ORG_SHAPE_RANK, Index>; | ||
| 675 | + | ||
| 676 | + /// Logical coordinate | ||
| 677 | + using Shape = Coord<RANK, Index>; | ||
| 678 | + | ||
| 679 | + /// Stride vector | ||
| 680 | + using Stride = Coord<RANK, LongIndex>; | ||
| 681 | + | ||
| 682 | +public: | ||
| 683 | + // Methods | ||
| 684 | + | ||
| 685 | + /// Constructor | ||
| 686 | + HOST_DEVICE constexpr | ||
| 687 | + zZ(Index orgRows = 0, /// Number of rows of origin matrices | ||
| 688 | + Index orgCols = 0, /// Number of cols of origin matrices | ||
| 689 | + Index rowsInFractal = 0, /// Number of rows inside the fractal | ||
| 690 | + Index rowsByFractal = 0, /// number of rows by the fractal | ||
| 691 | + Index colsInFractal = 0, /// number of cols inside the fractal | ||
| 692 | + Index colsByFractal = 0, /// number of cols by the fractal | ||
| 693 | + LongIndex strideRowsInFractal = 0, /// number of elements between adjacent rows inside the fractal | ||
| 694 | + LongIndex strideRowsByFractal = 0, /// number of elements between adjacent fractal rows | ||
| 695 | + LongIndex strideColsInFractal = 0, /// number of elements between adjacent cols inside the fractal | ||
| 696 | + LongIndex strideColsByFractal = 0) /// number of elements between adjacent fractal cols | ||
| 697 | + : orgShape_(MakeCoord(orgRows, orgCols)), | ||
| 698 | + shape_(MakeCoord(rowsInFractal, rowsByFractal, colsInFractal, colsByFractal)), | ||
| 699 | + stride_(MakeCoord(strideRowsInFractal, strideRowsByFractal, strideColsInFractal, strideColsByFractal)) {} | ||
| 700 | + | ||
| 701 | + /// Ctor | ||
| 702 | + HOST_DEVICE constexpr | ||
| 703 | + zZ(OrgShape orgShape, Shape shape, Stride stride) : orgShape_(orgShape), shape_(shape), stride_(stride) {} | ||
| 704 | + | ||
| 705 | + /// Make the layout of a coordinate (row, column) | ||
| 706 | + template <class Element> | ||
| 707 | + HOST_DEVICE constexpr | ||
| 708 | + static zZ MakeLayout(Index orgRows, Index orgCols) | ||
| 709 | + { | ||
| 710 | + constexpr uint32_t ELE_NUM_PER_C0 = static_cast<uint32_t>(BYTE_PER_C0) / static_cast<uint32_t>(sizeof(Element)); | ||
| 711 | + constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 712 | + Index rowsRound = RoundUp<C0_NUM_PER_FRACTAL>(orgRows); | ||
| 713 | + Index colsRound = RoundUp<ELE_NUM_PER_C0>(orgCols); | ||
| 714 | + return zZ(orgRows, | ||
| 715 | + orgCols, | ||
| 716 | + C0_NUM_PER_FRACTAL, | ||
| 717 | + rowsRound / C0_NUM_PER_FRACTAL, | ||
| 718 | + ELE_NUM_PER_C0, | ||
| 719 | + colsRound / ELE_NUM_PER_C0, | ||
| 720 | + ELE_NUM_PER_C0, | ||
| 721 | + colsRound * C0_NUM_PER_FRACTAL, | ||
| 722 | + 1, | ||
| 723 | + ELE_NUM_PER_FRACTAL); | ||
| 724 | + } | ||
| 725 | + | ||
| 726 | + /// Returns the offset of a coordinate in linear memory. | ||
| 727 | + /// Assumes coordinate has convention (row, column) | ||
| 728 | + HOST_DEVICE | ||
| 729 | + LongIndex GetOffset(MatrixCoord const &coord) const | ||
| 730 | + { | ||
| 731 | + return LongIndex(coord.row()) / shape_[0] * stride_[1] + LongIndex(coord.column()) / shape_[2] * stride_[3]; | ||
| 732 | + } | ||
| 733 | + | ||
| 734 | + /// Returns the origin shape of the layout | ||
| 735 | + HOST_DEVICE | ||
| 736 | + typename OrgShape::Index orgShape(int idx) const | ||
| 737 | + { | ||
| 738 | + return orgShape_[idx]; | ||
| 739 | + } | ||
| 740 | + | ||
| 741 | + /// Returns the origin shape of the layout | ||
| 742 | + HOST_DEVICE | ||
| 743 | + typename OrgShape::Index &orgShape(int idx) | ||
| 744 | + { | ||
| 745 | + return orgShape_[idx]; | ||
| 746 | + } | ||
| 747 | + | ||
| 748 | + /// Returns the shape of the layout | ||
| 749 | + HOST_DEVICE | ||
| 750 | + Shape shape() const | ||
| 751 | + { | ||
| 752 | + return shape_; | ||
| 753 | + } | ||
| 754 | + | ||
| 755 | + /// Returns the shape of the layout | ||
| 756 | + HOST_DEVICE | ||
| 757 | + Shape &shape() | ||
| 758 | + { | ||
| 759 | + return shape_; | ||
| 760 | + } | ||
| 761 | + | ||
| 762 | + /// Returns the shape of the layout | ||
| 763 | + HOST_DEVICE | ||
| 764 | + typename Shape::Index shape(int idx) const | ||
| 765 | + { | ||
| 766 | + return shape_[idx]; | ||
| 767 | + } | ||
| 768 | + | ||
| 769 | + /// Returns the shape of the layout | ||
| 770 | + HOST_DEVICE | ||
| 771 | + typename Shape::Index &shape(int idx) | ||
| 772 | + { | ||
| 773 | + return shape_[idx]; | ||
| 774 | + } | ||
| 775 | + | ||
| 776 | + /// Returns the stride of the layout | ||
| 777 | + HOST_DEVICE | ||
| 778 | + Stride stride() const | ||
| 779 | + { | ||
| 780 | + return stride_; | ||
| 781 | + } | ||
| 782 | + | ||
| 783 | + /// Returns the stride of the layout | ||
| 784 | + HOST_DEVICE | ||
| 785 | + Stride &stride() | ||
| 786 | + { | ||
| 787 | + return stride_; | ||
| 788 | + } | ||
| 789 | + | ||
| 790 | + /// Returns the stride of the layout | ||
| 791 | + HOST_DEVICE | ||
| 792 | + typename Stride::Index stride(int idx) const | ||
| 793 | + { | ||
| 794 | + return stride_[idx]; | ||
| 795 | + } | ||
| 796 | + | ||
| 797 | + /// Returns the stride of the layout | ||
| 798 | + HOST_DEVICE | ||
| 799 | + typename Stride::Index &stride(int idx) | ||
| 800 | + { | ||
| 801 | + return stride_[idx]; | ||
| 802 | + } | ||
| 803 | + | ||
| 804 | +private: | ||
| 805 | + /// Origin Shape data member | ||
| 806 | + OrgShape orgShape_; | ||
| 807 | + | ||
| 808 | + /// Shape data member | ||
| 809 | + Shape shape_; | ||
| 810 | + | ||
| 811 | + /// Stride data member | ||
| 812 | + Stride stride_; | ||
| 813 | +}; | ||
| 814 | + | ||
| 815 | +/// Mapping function for padding rowmajor matrices | ||
| 816 | +/// A special data layout designed to improve the efficiency of matrix operations in non-512B aligned scenarios. | ||
| 817 | +/// This layout is row-major within blocks and also row-major between blocks. | ||
| 818 | +struct PaddingRowMajor { | ||
| 819 | +public: | ||
| 820 | + /// Logical rank of tensor | ||
| 821 | + static constexpr int RANK = 4; | ||
| 822 | + | ||
| 823 | + /// Logical rank of orgshape | ||
| 824 | + static constexpr int ORG_SHAPE_RANK = 2; | ||
| 825 | + | ||
| 826 | + /// Index type used for coordinates | ||
| 827 | + using Index = uint32_t; | ||
| 828 | + | ||
| 829 | + /// Long index type used for offsets | ||
| 830 | + using LongIndex = int64_t; | ||
| 831 | + | ||
| 832 | + /// Logical coordinate | ||
| 833 | + using OrgShape = Coord<ORG_SHAPE_RANK, Index>; | ||
| 834 | + | ||
| 835 | + /// Logical coordinate | ||
| 836 | + using Shape = Coord<RANK, Index>; | ||
| 837 | + | ||
| 838 | + /// Stride vector | ||
| 839 | + using Stride = Coord<RANK, LongIndex>; | ||
| 840 | + | ||
| 841 | +public: | ||
| 842 | + /// Constructor | ||
| 843 | + HOST_DEVICE | ||
| 844 | + PaddingRowMajor(Index orgRows = 0, Index orgCols = 0, Index blockRows = 0, Index blockCols = 0) : | ||
| 845 | + orgShape_(MakeCoord(orgRows, orgCols)), | ||
| 846 | + shape_(MakeCoord(blockRows, CeilDiv(orgRows, blockRows), blockCols, CeilDiv(orgCols, blockCols))), | ||
| 847 | + stride_(MakeCoord((LongIndex)blockCols, (LongIndex)blockRows * (LongIndex)RoundUp(orgCols, blockCols), | ||
| 848 | + (LongIndex)1, (LongIndex)blockRows * (LongIndex)blockCols)) {} | ||
| 849 | + | ||
| 850 | + /// Returns the offset of a coordinate in linear memory. | ||
| 851 | + /// Assumes coordinate has convention (row, column) | ||
| 852 | + HOST_DEVICE | ||
| 853 | + LongIndex GetOffset(MatrixCoord const &coord) const | ||
| 854 | + { | ||
| 855 | + LongIndex blockRows = (LongIndex)shape_[0]; | ||
| 856 | + LongIndex blockCols = (LongIndex)shape_[2]; | ||
| 857 | + return (LongIndex)coord.row() / blockRows * stride_[1] | ||
| 858 | + + (LongIndex)coord.column() / blockCols * stride_[3] | ||
| 859 | + + (LongIndex)coord.row() % blockRows * stride_[0] | ||
| 860 | + + (LongIndex)coord.column() % blockCols; | ||
| 861 | + } | ||
| 862 | + | ||
| 863 | + HOST_DEVICE | ||
| 864 | + PaddingRowMajor GetTileLayout(MatrixCoord const &tileShape) const | ||
| 865 | + { | ||
| 866 | + return PaddingRowMajor(tileShape.row(), tileShape.column(), shape_[0], shape_[2]); | ||
| 867 | + } | ||
| 868 | + | ||
| 869 | + /// Returns the origin shape of the layout | ||
| 870 | + HOST_DEVICE | ||
| 871 | + typename OrgShape::Index orgShape(int idx) const | ||
| 872 | + { | ||
| 873 | + return orgShape_[idx]; | ||
| 874 | + } | ||
| 875 | + | ||
| 876 | + /// Returns the origin shape of the layout | ||
| 877 | + HOST_DEVICE | ||
| 878 | + typename OrgShape::Index &orgShape(int idx) | ||
| 879 | + { | ||
| 880 | + return orgShape_[idx]; | ||
| 881 | + } | ||
| 882 | + | ||
| 883 | + /// Returns the shape of the layout | ||
| 884 | + HOST_DEVICE | ||
| 885 | + Shape shape() const | ||
| 886 | + { | ||
| 887 | + return shape_; | ||
| 888 | + } | ||
| 889 | + | ||
| 890 | + /// Returns the shape of the layout | ||
| 891 | + HOST_DEVICE | ||
| 892 | + Shape &shape() | ||
| 893 | + { | ||
| 894 | + return shape_; | ||
| 895 | + } | ||
| 896 | + | ||
| 897 | + /// Returns the shape of the layout | ||
| 898 | + HOST_DEVICE | ||
| 899 | + typename Shape::Index shape(int idx) const | ||
| 900 | + { | ||
| 901 | + return shape_[idx]; | ||
| 902 | + } | ||
| 903 | + | ||
| 904 | + /// Returns the shape of the layout | ||
| 905 | + HOST_DEVICE | ||
| 906 | + typename Shape::Index &shape(int idx) | ||
| 907 | + { | ||
| 908 | + return shape_[idx]; | ||
| 909 | + } | ||
| 910 | + | ||
| 911 | + /// Returns the stride of the layout | ||
| 912 | + HOST_DEVICE | ||
| 913 | + Stride stride() const | ||
| 914 | + { | ||
| 915 | + return stride_; | ||
| 916 | + } | ||
| 917 | + | ||
| 918 | + /// Returns the stride of the layout | ||
| 919 | + HOST_DEVICE | ||
| 920 | + Stride &stride() | ||
| 921 | + { | ||
| 922 | + return stride_; | ||
| 923 | + } | ||
| 924 | + | ||
| 925 | + /// Returns the stride of the layout | ||
| 926 | + HOST_DEVICE | ||
| 927 | + typename Stride::Index stride(int idx) const | ||
| 928 | + { | ||
| 929 | + return stride_[idx]; | ||
| 930 | + } | ||
| 931 | + | ||
| 932 | + /// Returns the stride of the layout | ||
| 933 | + HOST_DEVICE | ||
| 934 | + typename Stride::Index &stride(int idx) | ||
| 935 | + { | ||
| 936 | + return stride_[idx]; | ||
| 937 | + } | ||
| 938 | + | ||
| 939 | +private: | ||
| 940 | + // | ||
| 941 | + // Data members | ||
| 942 | + // | ||
| 943 | + | ||
| 944 | + /// Origin Shape data member | ||
| 945 | + OrgShape orgShape_; | ||
| 946 | + | ||
| 947 | + /// Shape data member | ||
| 948 | + Shape shape_; | ||
| 949 | + | ||
| 950 | + /// Stride data member | ||
| 951 | + Stride stride_; | ||
| 952 | +}; | ||
| 953 | + | ||
| 954 | +/// Mapping function for padding columnmajor matrices | ||
| 955 | +/// A special data layout designed to improve the efficiency of matrix operations in non-512B aligned scenarios. | ||
| 956 | +/// This layout is column-major within blocks and also column-major between blocks. | ||
| 957 | +struct PaddingColumnMajor { | ||
| 958 | +public: | ||
| 959 | + /// Logical rank of tensor | ||
| 960 | + static constexpr int RANK = 4; | ||
| 961 | + | ||
| 962 | + /// Logical rank of orgshape | ||
| 963 | + static constexpr int ORG_SHAPE_RANK = 2; | ||
| 964 | + | ||
| 965 | + /// Index type used for coordinates | ||
| 966 | + using Index = uint32_t; | ||
| 967 | + | ||
| 968 | + /// Long index type used for offsets | ||
| 969 | + using LongIndex = int64_t; | ||
| 970 | + | ||
| 971 | + /// Logical coordinate | ||
| 972 | + using OrgShape = Coord<ORG_SHAPE_RANK, Index>; | ||
| 973 | + | ||
| 974 | + /// Logical coordinate | ||
| 975 | + using Shape = Coord<RANK, Index>; | ||
| 976 | + | ||
| 977 | + /// Stride vector | ||
| 978 | + using Stride = Coord<RANK, LongIndex>; | ||
| 979 | + | ||
| 980 | +public: | ||
| 981 | + /// Constructor | ||
| 982 | + HOST_DEVICE | ||
| 983 | + PaddingColumnMajor(Index orgRows = 0, Index orgCols = 0, Index blockRows = 0, Index blockCols = 0) : | ||
| 984 | + orgShape_(MakeCoord(orgRows, orgCols)), | ||
| 985 | + shape_(MakeCoord(blockRows, CeilDiv(orgRows, blockRows), blockCols, CeilDiv(orgCols, blockCols))), | ||
| 986 | + stride_(MakeCoord((LongIndex)1, (LongIndex)blockRows * (LongIndex)blockCols, (LongIndex)blockRows, | ||
| 987 | + (LongIndex)RoundUp(orgRows, blockRows) * (LongIndex)blockCols)) {} | ||
| 988 | + | ||
| 989 | + /// Returns the offset of a coordinate in linear memory. | ||
| 990 | + /// Assumes coordinate has convention (row, column) | ||
| 991 | + HOST_DEVICE | ||
| 992 | + LongIndex GetOffset(MatrixCoord const &coord) const | ||
| 993 | + { | ||
| 994 | + LongIndex blockRows = (LongIndex)shape_[0]; | ||
| 995 | + LongIndex blockCols = (LongIndex)shape_[2]; | ||
| 996 | + return (LongIndex)coord.row() / blockRows * stride_[1] | ||
| 997 | + + (LongIndex)coord.column() / blockCols * stride_[3] | ||
| 998 | + + (LongIndex)coord.row() % blockRows | ||
| 999 | + + (LongIndex)coord.column() % blockCols * stride_[2]; | ||
| 1000 | + } | ||
| 1001 | + | ||
| 1002 | + HOST_DEVICE | ||
| 1003 | + PaddingColumnMajor GetTileLayout(MatrixCoord const &tileShape) const | ||
| 1004 | + { | ||
| 1005 | + return PaddingColumnMajor(tileShape.row(), tileShape.column(), shape_[0], shape_[2]); | ||
| 1006 | + } | ||
| 1007 | + | ||
| 1008 | + /// Returns the origin shape of the layout | ||
| 1009 | + HOST_DEVICE | ||
| 1010 | + typename OrgShape::Index orgShape(int idx) const | ||
| 1011 | + { | ||
| 1012 | + return orgShape_[idx]; | ||
| 1013 | + } | ||
| 1014 | + | ||
| 1015 | + /// Returns the origin shape of the layout | ||
| 1016 | + HOST_DEVICE | ||
| 1017 | + typename OrgShape::Index &orgShape(int idx) | ||
| 1018 | + { | ||
| 1019 | + return orgShape_[idx]; | ||
| 1020 | + } | ||
| 1021 | + | ||
| 1022 | + /// Returns the shape of the layout | ||
| 1023 | + HOST_DEVICE | ||
| 1024 | + Shape shape() const | ||
| 1025 | + { | ||
| 1026 | + return shape_; | ||
| 1027 | + } | ||
| 1028 | + | ||
| 1029 | + /// Returns the shape of the layout | ||
| 1030 | + HOST_DEVICE | ||
| 1031 | + Shape &shape() | ||
| 1032 | + { | ||
| 1033 | + return shape_; | ||
| 1034 | + } | ||
| 1035 | + | ||
| 1036 | + /// Returns the shape of the layout | ||
| 1037 | + HOST_DEVICE | ||
| 1038 | + typename Shape::Index shape(int idx) const | ||
| 1039 | + { | ||
| 1040 | + return shape_[idx]; | ||
| 1041 | + } | ||
| 1042 | + | ||
| 1043 | + /// Returns the shape of the layout | ||
| 1044 | + HOST_DEVICE | ||
| 1045 | + typename Shape::Index &shape(int idx) | ||
| 1046 | + { | ||
| 1047 | + return shape_[idx]; | ||
| 1048 | + } | ||
| 1049 | + | ||
| 1050 | + /// Returns the stride of the layout | ||
| 1051 | + HOST_DEVICE | ||
| 1052 | + Stride stride() const | ||
| 1053 | + { | ||
| 1054 | + return stride_; | ||
| 1055 | + } | ||
| 1056 | + | ||
| 1057 | + /// Returns the stride of the layout | ||
| 1058 | + HOST_DEVICE | ||
| 1059 | + Stride &stride() | ||
| 1060 | + { | ||
| 1061 | + return stride_; | ||
| 1062 | + } | ||
| 1063 | + | ||
| 1064 | + /// Returns the stride of the layout | ||
| 1065 | + HOST_DEVICE | ||
| 1066 | + typename Stride::Index stride(int idx) const | ||
| 1067 | + { | ||
| 1068 | + return stride_[idx]; | ||
| 1069 | + } | ||
| 1070 | + | ||
| 1071 | + /// Returns the stride of the layout | ||
| 1072 | + HOST_DEVICE | ||
| 1073 | + typename Stride::Index &stride(int idx) | ||
| 1074 | + { | ||
| 1075 | + return stride_[idx]; | ||
| 1076 | + } | ||
| 1077 | + | ||
| 1078 | + | ||
| 1079 | +private: | ||
| 1080 | + // | ||
| 1081 | + // Data members | ||
| 1082 | + // | ||
| 1083 | + | ||
| 1084 | + /// Origin Shape data member | ||
| 1085 | + OrgShape orgShape_; | ||
| 1086 | + | ||
| 1087 | + /// Shape data member | ||
| 1088 | + Shape shape_; | ||
| 1089 | + | ||
| 1090 | + /// Stride data member | ||
| 1091 | + Stride stride_; | ||
| 1092 | +}; | ||
| 1093 | + | ||
| 1094 | +/////////////////////// | ||
| 1095 | +// new add layout nN | ||
| 1096 | +// nN layout | ||
| 1097 | +struct nN { | ||
| 1098 | +public: | ||
| 1099 | + /// Logical rank of tensor | ||
| 1100 | + static constexpr int RANK = 4; | ||
| 1101 | + | ||
| 1102 | + /// Index type used for coordinates | ||
| 1103 | + using Index = uint32_t; | ||
| 1104 | + | ||
| 1105 | + /// Long index type used for offsets | ||
| 1106 | + using LongIndex = int64_t; | ||
| 1107 | + | ||
| 1108 | + /// Logical rank of orgshape | ||
| 1109 | + static constexpr int ORG_SHAPE_RANK = 2; | ||
| 1110 | + | ||
| 1111 | + /// Logical coordinate | ||
| 1112 | + using OrgShape = Coord<ORG_SHAPE_RANK, Index>; | ||
| 1113 | + | ||
| 1114 | + /// Logical coordinate | ||
| 1115 | + using Shape = Coord<RANK, Index>; | ||
| 1116 | + | ||
| 1117 | + /// Stride vector | ||
| 1118 | + using Stride = Coord<RANK, LongIndex>; | ||
| 1119 | + | ||
| 1120 | +public: | ||
| 1121 | + // Methods | ||
| 1122 | + | ||
| 1123 | + /// Constructor | ||
| 1124 | + HOST_DEVICE | ||
| 1125 | + nN(Index orgRows = 0, /// Number of rows of origin matrices | ||
| 1126 | + Index orgCols = 0, /// Number of cols of origin matrices | ||
| 1127 | + | ||
| 1128 | + Index rowsInFractal = 0, /// Number of rows inside the fractal | ||
| 1129 | + Index rowsByFractal = 0, /// number of rows by the fractal | ||
| 1130 | + Index colsInFractal = 0, /// number of cols inside the fractal | ||
| 1131 | + Index colsByFractal = 0, /// number of cols by the fractal | ||
| 1132 | + | ||
| 1133 | + LongIndex strideRowsInFractal = 0, /// number of elements between adjacent rows inside the fractal | ||
| 1134 | + LongIndex strideRowsByFractal = 0, /// number of elements between adjacent fractal rows | ||
| 1135 | + LongIndex strideColsInFractal = 0, /// number of elements between adjacent cols inside the fractal | ||
| 1136 | + LongIndex strideColsByFractal = 0) /// number of elements between adjacent fractal cols | ||
| 1137 | + : orgShape_(MakeCoord(orgRows, orgCols)), | ||
| 1138 | + shape_(MakeCoord(rowsInFractal, rowsByFractal, colsInFractal, colsByFractal)), | ||
| 1139 | + stride_(MakeCoord(strideRowsInFractal, strideRowsByFractal, strideColsInFractal, strideColsByFractal)) { | ||
| 1140 | + } | ||
| 1141 | + | ||
| 1142 | + /// Ctor | ||
| 1143 | + HOST_DEVICE | ||
| 1144 | + nN(OrgShape orgShape, Shape shape, Stride stride) | ||
| 1145 | + : orgShape_(orgShape), shape_(shape), stride_(stride) {} | ||
| 1146 | + | ||
| 1147 | + /// Make the layout of a coordinate (row, column) | ||
| 1148 | + template <class Element> | ||
| 1149 | + HOST_DEVICE static nN MakeLayout(Index orgRows, Index orgCols) { | ||
| 1150 | + static constexpr uint32_t ELE_NUM_PER_C0 = BYTE_PER_C0 / sizeof(Element); | ||
| 1151 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = BYTE_PER_FRACTAL / sizeof(Element); | ||
| 1152 | + Index rowsRound = RoundUp<ELE_NUM_PER_C0>(orgRows); | ||
| 1153 | + Index colsRound = RoundUp<C0_NUM_PER_FRACTAL>(orgCols); | ||
| 1154 | + return nN(orgRows, | ||
| 1155 | + orgCols, | ||
| 1156 | + | ||
| 1157 | + ELE_NUM_PER_C0, | ||
| 1158 | + rowsRound / ELE_NUM_PER_C0, | ||
| 1159 | + C0_NUM_PER_FRACTAL, | ||
| 1160 | + colsRound / C0_NUM_PER_FRACTAL, | ||
| 1161 | + | ||
| 1162 | + 1, | ||
| 1163 | + ELE_NUM_PER_FRACTAL, | ||
| 1164 | + ELE_NUM_PER_C0, | ||
| 1165 | + rowsRound * C0_NUM_PER_FRACTAL); | ||
| 1166 | + } | ||
| 1167 | + | ||
| 1168 | + /// Returns the offset of a coordinate in linear memory. | ||
| 1169 | + /// Assumes coordinate has convention (row, column) | ||
| 1170 | + HOST_DEVICE | ||
| 1171 | + LongIndex GetOffset(MatrixCoord const& coord) const { | ||
| 1172 | + return LongIndex(coord.row()) / shape_[0] * stride_[1] + LongIndex(coord.column()) / shape_[2] * stride_[3]; | ||
| 1173 | + } | ||
| 1174 | + | ||
| 1175 | + /// Returns the origin shape of the layout | ||
| 1176 | + HOST_DEVICE | ||
| 1177 | + typename OrgShape::Index orgShape(int idx) const { | ||
| 1178 | + return orgShape_[idx]; | ||
| 1179 | + } | ||
| 1180 | + | ||
| 1181 | + /// Returns the origin shape of the layout | ||
| 1182 | + HOST_DEVICE | ||
| 1183 | + typename OrgShape::Index& orgShape(int idx) { | ||
| 1184 | + return orgShape_[idx]; | ||
| 1185 | + } | ||
| 1186 | + | ||
| 1187 | + /// Returns the shape of the layout | ||
| 1188 | + HOST_DEVICE | ||
| 1189 | + Shape shape() const { | ||
| 1190 | + return shape_; | ||
| 1191 | + } | ||
| 1192 | + | ||
| 1193 | + /// Returns the shape of the layout | ||
| 1194 | + HOST_DEVICE | ||
| 1195 | + Shape& shape() { | ||
| 1196 | + return shape_; | ||
| 1197 | + } | ||
| 1198 | + | ||
| 1199 | + /// Returns the shape of the layout | ||
| 1200 | + HOST_DEVICE | ||
| 1201 | + typename Shape::Index shape(int idx) const { | ||
| 1202 | + return shape_[idx]; | ||
| 1203 | + } | ||
| 1204 | + | ||
| 1205 | + /// Returns the shape of the layout | ||
| 1206 | + HOST_DEVICE | ||
| 1207 | + typename Shape::Index& shape(int idx) { | ||
| 1208 | + return shape_[idx]; | ||
| 1209 | + } | ||
| 1210 | + | ||
| 1211 | + /// Returns the stride of the layout | ||
| 1212 | + HOST_DEVICE | ||
| 1213 | + Stride stride() const { | ||
| 1214 | + return stride_; | ||
| 1215 | + } | ||
| 1216 | + | ||
| 1217 | + /// Returns the stride of the layout | ||
| 1218 | + HOST_DEVICE | ||
| 1219 | + Stride& stride() { | ||
| 1220 | + return stride_; | ||
| 1221 | + } | ||
| 1222 | + | ||
| 1223 | + /// Returns the stride of the layout | ||
| 1224 | + HOST_DEVICE | ||
| 1225 | + typename Stride::Index stride(int idx) const { | ||
| 1226 | + return stride_[idx]; | ||
| 1227 | + } | ||
| 1228 | + | ||
| 1229 | + /// Returns the stride of the layout | ||
| 1230 | + HOST_DEVICE | ||
| 1231 | + typename Stride::Index& stride(int idx) { | ||
| 1232 | + return stride_[idx]; | ||
| 1233 | + } | ||
| 1234 | + | ||
| 1235 | +private: | ||
| 1236 | + /// Origin Shape data member | ||
| 1237 | + OrgShape orgShape_; | ||
| 1238 | + | ||
| 1239 | + /// Shape data member | ||
| 1240 | + Shape shape_; | ||
| 1241 | + | ||
| 1242 | + /// Stride data member | ||
| 1243 | + Stride stride_; | ||
| 1244 | +}; | ||
| 1245 | +} // namespace NpuArch::layout | ||
| 1246 | + | ||
| 1247 | + | ||
| @@ -0,0 +1,133 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace NpuArch::layout | ||
| 18 | +{ | ||
| 19 | + | ||
| 20 | +struct VectorLayout { | ||
| 21 | +public: | ||
| 22 | + /// Logical rank of tensor | ||
| 23 | + static constexpr int RANK = 1; | ||
| 24 | + | ||
| 25 | + /// Index type used for coordinates | ||
| 26 | + using Index = uint32_t; | ||
| 27 | + | ||
| 28 | + /// Long index type used for offsets | ||
| 29 | + using LongIndex = int64_t; | ||
| 30 | + | ||
| 31 | + /// Shape vector | ||
| 32 | + using Shape = Coord<RANK, Index>; | ||
| 33 | + | ||
| 34 | + /// Stride vector | ||
| 35 | + using Stride = Coord<RANK, LongIndex>; | ||
| 36 | + | ||
| 37 | + /// Logical coordinate | ||
| 38 | + using TensorCoord = Coord<RANK, Index>; | ||
| 39 | + | ||
| 40 | +public: | ||
| 41 | + // Methods | ||
| 42 | + | ||
| 43 | + HOST_DEVICE | ||
| 44 | + VectorLayout(Index size = 0) : shape_(MakeCoord(size)), stride_(MakeCoord(LongIndex(1))) {} | ||
| 45 | + | ||
| 46 | + HOST_DEVICE | ||
| 47 | + VectorLayout(Shape shape, Stride stride) : shape_(shape), stride_(stride) {} | ||
| 48 | + | ||
| 49 | + template <class Element> | ||
| 50 | + HOST_DEVICE | ||
| 51 | + static VectorLayout MakeLayoutInUb(TensorCoord const &tileShape) | ||
| 52 | + { | ||
| 53 | + return VectorLayout{RoundUp<BYTE_PER_BLK / sizeof(Element)>(tileShape[0])}; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + HOST_DEVICE | ||
| 57 | + LongIndex GetOffset(TensorCoord const &coord) const | ||
| 58 | + { | ||
| 59 | + return stride_[0] * coord[0]; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + /// Returns the layout of a tile_common. | ||
| 63 | + HOST_DEVICE | ||
| 64 | + VectorLayout GetTileLayout(TensorCoord const &tileShape) const | ||
| 65 | + { | ||
| 66 | + return VectorLayout(tileShape, stride()); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /// Returns the shape of the layout | ||
| 70 | + HOST_DEVICE | ||
| 71 | + Shape shape() const | ||
| 72 | + { | ||
| 73 | + return shape_; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + /// Returns the shape of the layout | ||
| 77 | + HOST_DEVICE | ||
| 78 | + Shape &shape() | ||
| 79 | + { | ||
| 80 | + return shape_; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + /// Returns the shape of the layout | ||
| 84 | + HOST_DEVICE | ||
| 85 | + typename Shape::Index shape(int idx) const | ||
| 86 | + { | ||
| 87 | + return shape_[idx]; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /// Returns the shape of the layout | ||
| 91 | + HOST_DEVICE | ||
| 92 | + typename Shape::Index &shape(int idx) | ||
| 93 | + { | ||
| 94 | + return shape_[idx]; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + /// Returns the stride of the layout | ||
| 98 | + HOST_DEVICE | ||
| 99 | + Stride stride() const | ||
| 100 | + { | ||
| 101 | + return stride_; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + /// Returns the stride of the layout | ||
| 105 | + HOST_DEVICE | ||
| 106 | + Stride &stride() | ||
| 107 | + { | ||
| 108 | + return stride_; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + /// Returns the stride of the layout | ||
| 112 | + HOST_DEVICE | ||
| 113 | + typename Stride::Index stride(int idx) const | ||
| 114 | + { | ||
| 115 | + return stride_[idx]; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + /// Returns the stride of the layout | ||
| 119 | + HOST_DEVICE | ||
| 120 | + typename Stride::Index &stride(int idx) | ||
| 121 | + { | ||
| 122 | + return stride_[idx]; | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | +private: | ||
| 126 | + /// Stride data member | ||
| 127 | + Shape shape_; | ||
| 128 | + Stride stride_; | ||
| 129 | +}; | ||
| 130 | + | ||
| 131 | +} // namespace NpuArch::layout | ||
| 132 | + | ||
| 133 | + | ||
| @@ -0,0 +1,108 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file matrix_coord.hpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace NpuArch { | ||
| 22 | + | ||
| 23 | +template < | ||
| 24 | + uint32_t ROW_ = 1, | ||
| 25 | + uint32_t COLUMN_ = 1 | ||
| 26 | +> | ||
| 27 | +struct MatrixShape { | ||
| 28 | + static constexpr uint32_t ROW = ROW_; | ||
| 29 | + static constexpr uint32_t COLUMN = COLUMN_; | ||
| 30 | + | ||
| 31 | + static constexpr int64_t COUNT = ROW * COLUMN; | ||
| 32 | + | ||
| 33 | + HOST_DEVICE | ||
| 34 | + static Coord<2> ToCoord() | ||
| 35 | + { | ||
| 36 | + return MakeCoord(ROW, COLUMN); | ||
| 37 | + } | ||
| 38 | +}; | ||
| 39 | + | ||
| 40 | +/// MatrixCoord wraps Coord<2, uint32_t> to provide a helper for accessing named dimensions. Classes | ||
| 41 | +/// expecting a coordinate in the rank=2 index space of a matrix should use MatrixCoord. | ||
| 42 | +struct MatrixCoord : public Coord<2, uint32_t> { | ||
| 43 | + /// Integer-valued index | ||
| 44 | + using Index = uint32_t; | ||
| 45 | + | ||
| 46 | + /// Base type is a Coord of rank=2 | ||
| 47 | + using Base = Coord<2, Index>; | ||
| 48 | + | ||
| 49 | + /// LongIndex type | ||
| 50 | + using LongIndex = typename Base::LongIndex; | ||
| 51 | + | ||
| 52 | + /// Rows dimension | ||
| 53 | + static constexpr uint32_t ROW_INDEX = 0; | ||
| 54 | + | ||
| 55 | + /// Columns dimension | ||
| 56 | + static constexpr uint32_t COLUMN_INDEX = 1; | ||
| 57 | + | ||
| 58 | + /// Default ctor | ||
| 59 | + HOST_DEVICE | ||
| 60 | + MatrixCoord() {} | ||
| 61 | + | ||
| 62 | + /// Constructs from Coord<2> | ||
| 63 | + HOST_DEVICE | ||
| 64 | + MatrixCoord(Coord<2, Index> const &coord) : Base(coord) {} | ||
| 65 | + | ||
| 66 | + /// Helper to construct from a row and column | ||
| 67 | + HOST_DEVICE | ||
| 68 | + MatrixCoord(Index row, Index column) : Base(MakeCoord(row, column)) {} | ||
| 69 | + | ||
| 70 | + /// Helper to construct from a row and column, which are LongIndex based | ||
| 71 | + HOST_DEVICE | ||
| 72 | + MatrixCoord(LongIndex row, LongIndex column) : Base(MakeCoord(Index(row), Index(column))) {} | ||
| 73 | + | ||
| 74 | + /// Returns the row of the coordinate | ||
| 75 | + HOST_DEVICE | ||
| 76 | + Index const &row() const { return this->At(ROW_INDEX); } | ||
| 77 | + | ||
| 78 | + /// Returns the row of the coordinate | ||
| 79 | + HOST_DEVICE | ||
| 80 | + Index &row() { return this->At(ROW_INDEX); } | ||
| 81 | + | ||
| 82 | + /// Returns the column of the coordinate | ||
| 83 | + HOST_DEVICE | ||
| 84 | + Index const &column() const { return this->At(COLUMN_INDEX); } | ||
| 85 | + | ||
| 86 | + /// Returns the column of the coordinate | ||
| 87 | + HOST_DEVICE | ||
| 88 | + Index &column() { return this->At(COLUMN_INDEX); } | ||
| 89 | + | ||
| 90 | + /// Element-wise addition | ||
| 91 | + HOST_DEVICE | ||
| 92 | + MatrixCoord operator+(Base const &b) const | ||
| 93 | + { | ||
| 94 | + return MatrixCoord(Base::operator+(b)); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + /// In-place addition | ||
| 98 | + HOST_DEVICE | ||
| 99 | + MatrixCoord &operator+=(Base const &b) | ||
| 100 | + { | ||
| 101 | + Base::operator+=(b); | ||
| 102 | + return *this; | ||
| 103 | + } | ||
| 104 | +}; | ||
| 105 | + | ||
| 106 | +} // namespace NpuArch | ||
| 107 | + | ||
| 108 | + | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +namespace NpuArch{ | ||
| 15 | + | ||
| 16 | +enum class Status{ kSuccess, kInvalid }; | ||
| 17 | + | ||
| 18 | +} // namespace NpuArch | ||
| 19 | + | ||
| 20 | + | ||
| @@ -0,0 +1,60 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +extern "C" __global__ __aicore__ void eagle_quant_block_sparse_attention(__gm__ uint8_t* query, __gm__ uint8_t* key, __gm__ uint8_t* value, | ||
| 17 | + __gm__ uint8_t* blockSparseMask, __gm__ uint8_t* mask, __gm__ uint8_t* blockShape, | ||
| 18 | + __gm__ uint8_t* actualSeqLengths, __gm__ uint8_t* actualSeqLengthsKv, __gm__ uint8_t* blockTable, | ||
| 19 | + __gm__ uint8_t* query_scale, __gm__ uint8_t* key_scale, __gm__ uint8_t* value_scale, | ||
| 20 | + __gm__ uint8_t* attentionOut, __gm__ uint8_t* softmaxLse, __gm__ uint8_t* workspace, __gm__ uint8_t* tiling) | ||
| 21 | +{ | ||
| 22 | + if (TILING_KEY_VAR >= RFA_BASE_TILING) { | ||
| 23 | + __gm__ uint8_t *user = AscendC::GetUserWorkspace(workspace); | ||
| 24 | + KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_MIX_AIC_1_2); | ||
| 25 | + // 读取tilingKey进行kernel分发 | ||
| 26 | + __gm__ EagleQuantBlockSparseAttentionTilingData *tilingDataPtr = | ||
| 27 | + reinterpret_cast<__gm__ EagleQuantBlockSparseAttentionTilingData *>(tiling); | ||
| 28 | + uint64_t tilingKey = tilingDataPtr->tilingKey; | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + TILING_KEY_IS(QKINT8_VFP8E4M3_QTND_KVTND_NOCACHE_SMF16_REF32_NOMASK_KEY); | ||
| 32 | + TILING_KEY_IS(QKINT8_VFP8E4M3_QBNSD_KVBNSD_NOCACHE_SMF16_REF32_NOMASK_KEY); | ||
| 33 | + TILING_KEY_IS(QKINT8_VFP8E4M3_QTND_KVTND_NOCACHE_SMF16_REF32_OBF16_NOMASK_KEY); | ||
| 34 | + TILING_KEY_IS(QKINT8_VFP8E4M3_QBNSD_KVBNSD_NOCACHE_SMF16_REF32_OBF16_NOMASK_KEY); | ||
| 35 | + | ||
| 36 | + BsaInferIntfRegular< | ||
| 37 | + int8_t, float8_e4m3_t, half, half, float, BsaKernelArch35::Format::TND, BsaKernelArch35::Format::TND>( | ||
| 38 | + query, key, value, mask, blockTable, query_scale, key_scale, value_scale, attentionOut, | ||
| 39 | + actualSeqLengths, actualSeqLengthsKv, blockSparseMask, user, tiling); | ||
| 40 | + | ||
| 41 | + BsaInferIntfRegular< | ||
| 42 | + int8_t, float8_e4m3_t, half, half, float, BsaKernelArch35::Format::BNSD, BsaKernelArch35::Format::BNSD>( | ||
| 43 | + query, key, value, mask, blockTable, query_scale, key_scale, value_scale, attentionOut, | ||
| 44 | + actualSeqLengths, actualSeqLengthsKv, blockSparseMask, user, tiling); | ||
| 45 | + | ||
| 46 | + BsaInferIntfRegular< | ||
| 47 | + int8_t, float8_e4m3_t, bfloat16_t, half, float, BsaKernelArch35::Format::TND, BsaKernelArch35::Format::TND>( | ||
| 48 | + query, key, value, mask, blockTable, query_scale, key_scale, value_scale, attentionOut, | ||
| 49 | + actualSeqLengths, actualSeqLengthsKv, blockSparseMask, user, tiling); | ||
| 50 | + | ||
| 51 | + BsaInferIntfRegular< | ||
| 52 | + int8_t, float8_e4m3_t, bfloat16_t, half, float, BsaKernelArch35::Format::BNSD, BsaKernelArch35::Format::BNSD>( | ||
| 53 | + query, key, value, mask, blockTable, query_scale, key_scale, value_scale, attentionOut, | ||
| 54 | + actualSeqLengths, actualSeqLengthsKv, blockSparseMask, user, tiling); | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + } | ||
| 59 | +} | ||
| 60 | + | ||
| @@ -0,0 +1,243 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file eagle_quant_block_sparse_attention_interface.cpp | ||
| 13 | + * \brief Block Sparse Attention Interface | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +using namespace NpuArch; | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +namespace BlockSparse { | ||
| 28 | +template < | ||
| 29 | + typename InputDtype = half, | ||
| 30 | + typename SoftmaxDtype = float, | ||
| 31 | + Epilogue::LseMode lseMode = Epilogue::LseMode::NONE, | ||
| 32 | + uint32_t QueryLayout = 0, // 0=TND, 1=BNSD | ||
| 33 | + uint32_t KvCacheLayout = 0> // 0=TND, 1=BNSD | ||
| 34 | +__global__ __aicore__ void EagleQuantBlockSparseAttentionInfer( | ||
| 35 | + GM_ADDR q, | ||
| 36 | + GM_ADDR k, | ||
| 37 | + GM_ADDR v, | ||
| 38 | + GM_ADDR blockSparseMask, | ||
| 39 | + GM_ADDR mask, | ||
| 40 | + GM_ADDR blockTables, | ||
| 41 | + GM_ADDR o, | ||
| 42 | + GM_ADDR actualQseqlen, | ||
| 43 | + GM_ADDR actualKvseqlen, | ||
| 44 | + GM_ADDR blockShape, | ||
| 45 | + GM_ADDR workspace, // S matrix (QK^T result) | ||
| 46 | + GM_ADDR lse, | ||
| 47 | + GM_ADDR tiling) | ||
| 48 | +{ | ||
| 49 | + using ArchTag = Arch::AtlasA2; | ||
| 50 | + using ElementQ = InputDtype; | ||
| 51 | + using LayoutQ = layout::RowMajor; | ||
| 52 | + using ElementK = InputDtype; | ||
| 53 | + using LayoutK = layout::ColumnMajor; | ||
| 54 | + using ElementV = InputDtype; | ||
| 55 | + using LayoutV = layout::RowMajor; | ||
| 56 | + using ElementS = SoftmaxDtype; | ||
| 57 | + using LayoutS = layout::RowMajor; | ||
| 58 | + using ElementP = InputDtype; | ||
| 59 | + using LayoutP = layout::RowMajor; | ||
| 60 | + using ElementO = InputDtype; | ||
| 61 | + using LayoutO = layout::RowMajor; | ||
| 62 | + using ElementLse = float; | ||
| 63 | + using LayoutLse = layout::RowMajor; | ||
| 64 | + using ElementMask = int8_t; | ||
| 65 | + using LayoutMask = layout::RowMajor; | ||
| 66 | + using ElementOTmp = SoftmaxDtype; | ||
| 67 | + using LayoutOTmp = layout::RowMajor; | ||
| 68 | + using ElementUpdate = SoftmaxDtype; | ||
| 69 | + using LayoutUpdate = layout::RowMajor; | ||
| 70 | + | ||
| 71 | + // Use sparse-specific dispatch policies | ||
| 72 | + using L1TileShapeQK = GemmShape<Q_TILE_CEIL, 128, 128>; | ||
| 73 | + using L0TileShapeQK = GemmShape<128, 128, 128>; | ||
| 74 | + using DispatchPolicyQK = Gemm::MmadAtlasA2SFAIQK<false, false>; | ||
| 75 | + using QType = Gemm::GemmType<ElementQ, LayoutQ>; | ||
| 76 | + using KType = Gemm::GemmType<ElementK, LayoutK>; | ||
| 77 | + using SType = Gemm::GemmType<ElementS, LayoutS>; | ||
| 78 | + using BlockMmadQK = Gemm::Block::BlockMmad<DispatchPolicyQK, L1TileShapeQK, L0TileShapeQK, | ||
| 79 | + QType, KType, SType>; | ||
| 80 | + | ||
| 81 | + using L1TileShapePV = GemmShape<128, 128, 256>; | ||
| 82 | + using L0TileShapePV = GemmShape<128, 128, 128>; | ||
| 83 | + using DispatchPolicyPV = Gemm::MmadAtlasA2SFAIPV<false, false>; | ||
| 84 | + using PType = Gemm::GemmType<ElementP, LayoutP>; | ||
| 85 | + using VType = Gemm::GemmType<ElementV, LayoutV>; | ||
| 86 | + using OTmpType = Gemm::GemmType<ElementOTmp, LayoutOTmp>; | ||
| 87 | + using BlockMmadPV = Gemm::Block::BlockMmad<DispatchPolicyPV, L1TileShapePV, L0TileShapePV, | ||
| 88 | + PType, VType, OTmpType>; | ||
| 89 | + | ||
| 90 | + // Epilogue policies for sparse attention | ||
| 91 | + using DispatchPolicyOnlineSoftmax = Epilogue::EpilogueAtlasA2OnlineSoftmax<lseMode, SoftmaxDtype>; | ||
| 92 | + using MaskType = Gemm::GemmType<ElementMask, LayoutMask>; | ||
| 93 | + using EpilogueOnlineSoftmax = Epilogue::Block::BlockEpilogue<DispatchPolicyOnlineSoftmax, | ||
| 94 | + PType, SType, MaskType>; | ||
| 95 | + using DispatchPolicyRescaleO = Epilogue::EpilogueAtlasA2RescaleO<lseMode, SoftmaxDtype>; | ||
| 96 | + using OType = Gemm::GemmType<ElementO, LayoutO>; | ||
| 97 | + using OUpdateType = Gemm::GemmType<ElementUpdate, LayoutUpdate>; | ||
| 98 | + using LseType = Gemm::GemmType<ElementLse, LayoutLse>; | ||
| 99 | + using EpilogueRescaleO = Epilogue::Block::BlockEpilogue<DispatchPolicyRescaleO, | ||
| 100 | + OType, OTmpType, OUpdateType, LseType>; | ||
| 101 | + | ||
| 102 | + // Kernel instantiation | ||
| 103 | + using EagleQuantBlockSparseAttentionKernelType = EagleQuantBlockSparseAttentionKernel<BlockMmadQK, BlockMmadPV, | ||
| 104 | + EpilogueOnlineSoftmax, | ||
| 105 | + EpilogueRescaleO, | ||
| 106 | + false, // PAGED_CACHE_FLAG | ||
| 107 | + QueryLayout, // QUERY_LAYOUT | ||
| 108 | + KvCacheLayout>; // KV_CACHE_LAYOUT | ||
| 109 | + EagleQuantBlockSparseAttentionKernelParams params{q, k, v, blockSparseMask, mask, blockTables, actualQseqlen, actualKvseqlen, | ||
| 110 | + o, lse, workspace, tiling}; | ||
| 111 | + | ||
| 112 | + // Call block sparse attention kernel | ||
| 113 | + EagleQuantBlockSparseAttentionKernelType blockSparseAttenInfer; | ||
| 114 | + blockSparseAttenInfer(params); | ||
| 115 | +} | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | + | ||
| 119 | + | ||
| 120 | +// Lookup helper for ElementP type selection based on ElementQ and ElementV | ||
| 121 | +template <typename QType, typename VType, typename DefaultType> | ||
| 122 | +struct ElementPTypeLookup { | ||
| 123 | + using type = DefaultType; | ||
| 124 | +}; | ||
| 125 | + | ||
| 126 | +template <typename DefaultType> | ||
| 127 | +struct ElementPTypeLookup<int8_t, float8_e4m3_t, DefaultType> { | ||
| 128 | + using type = float8_e4m3_t; | ||
| 129 | +}; | ||
| 130 | + | ||
| 131 | +template <typename QType, typename KType, typename VType, typename OUTPODType> | ||
| 132 | +struct GetQuantMode { | ||
| 133 | + static constexpr int value = 0; | ||
| 134 | +}; | ||
| 135 | + | ||
| 136 | +template <> | ||
| 137 | +struct GetQuantMode<int8_t, int8_t, float8_e4m3_t, bfloat16_t> { | ||
| 138 | + static constexpr int value = 1; | ||
| 139 | +}; | ||
| 140 | + | ||
| 141 | +template <> | ||
| 142 | +struct GetQuantMode<int8_t, int8_t, float8_e4m3_t, half> { | ||
| 143 | + static constexpr int value = 1; | ||
| 144 | +}; | ||
| 145 | + | ||
| 146 | + | ||
| 147 | +template <int quantMode> | ||
| 148 | +struct QKScaleGranularitySelector { | ||
| 149 | + static constexpr NpuArch::Gemm::Tile::ScaleGranularity value = NpuArch::Gemm::Tile::ScaleGranularity::NO_QUANT; | ||
| 150 | +}; | ||
| 151 | + | ||
| 152 | +template <> | ||
| 153 | +struct QKScaleGranularitySelector<1> { | ||
| 154 | + static constexpr NpuArch::Gemm::Tile::ScaleGranularity value = NpuArch::Gemm::Tile::ScaleGranularity::PER_TENSOR; | ||
| 155 | +}; | ||
| 156 | + | ||
| 157 | +template <int quantMode> | ||
| 158 | +struct PVScaleGranularitySelector { | ||
| 159 | + static constexpr NpuArch::Gemm::Tile::ScaleGranularity value = NpuArch::Gemm::Tile::ScaleGranularity::NO_QUANT; | ||
| 160 | +}; | ||
| 161 | + | ||
| 162 | +template <> | ||
| 163 | +struct PVScaleGranularitySelector<1> { | ||
| 164 | + static constexpr NpuArch::Gemm::Tile::ScaleGranularity value = NpuArch::Gemm::Tile::ScaleGranularity::NO_QUANT; | ||
| 165 | +}; | ||
| 166 | + | ||
| 167 | +using namespace BsaKernelArch35; | ||
| 168 | + | ||
| 169 | +template <class InQKDtype, class InVDtype, class OUTPODType, class SMDtype, class REDtype, Format qFormat, Format kvFormat> | ||
| 170 | +__global__ __aicore__ void BsaInferIntfRegular( | ||
| 171 | + GM_ADDR q, GM_ADDR k, GM_ADDR v, GM_ADDR mask, GM_ADDR blockTables, | ||
| 172 | + GM_ADDR query_scale, GM_ADDR key_scale, GM_ADDR value_scale, | ||
| 173 | + GM_ADDR o, GM_ADDR actualQseqlen, GM_ADDR actualKvseqlen, | ||
| 174 | + GM_ADDR blockSparseMask, GM_ADDR workspace, | ||
| 175 | + GM_ADDR tiling | ||
| 176 | +) { | ||
| 177 | + using ArchTag = Arch::AtlasA5; | ||
| 178 | + using ElementSparseMask = uint8_t; | ||
| 179 | + using ElementSparseIdx = int32_t; | ||
| 180 | + using ElementSparseCount = int32_t; | ||
| 181 | + using ElementQ = InQKDtype; | ||
| 182 | + using ElementK = InQKDtype; | ||
| 183 | + using ElementV = InVDtype; | ||
| 184 | + using ElementS = SMDtype; | ||
| 185 | + using ElementP = typename ElementPTypeLookup<ElementQ, ElementV, OUTPODType>::type; | ||
| 186 | + using ElementO = OUTPODType; | ||
| 187 | + using ElementOTmp = REDtype; | ||
| 188 | + // layout tags | ||
| 189 | + using LayoutQ = layout::RowMajor; | ||
| 190 | + using LayoutK = layout::ColumnMajor; | ||
| 191 | + // S is rowMajor on UB(dst) | ||
| 192 | + using LayoutS = layout::RowMajor; | ||
| 193 | + // P is actually zN on UB(src), since there is no nd2nz in MTE1 | ||
| 194 | + //tODO后续增加一个selector,支持nz和zn | ||
| 195 | + using LayoutPDummy = layout::nZ; | ||
| 196 | + using LayoutV = layout::RowMajor; | ||
| 197 | + using LayoutO = layout::RowMajor; | ||
| 198 | + // OTmp is rowMajor on UB(dst) | ||
| 199 | + using LayoutOTmp = layout::RowMajor; | ||
| 200 | + using LayoutSparseIdx = layout::RowMajor; | ||
| 201 | + using LayoutSparseCount = layout::RowMajor; | ||
| 202 | + // block mask pre-process | ||
| 203 | + using DispatchPolicyMask2Idx = Epilogue::EpilogueBsaMask2Idx; | ||
| 204 | + using EpilogueMask2Idx = Epilogue::Block::BlockEpilogue< | ||
| 205 | + DispatchPolicyMask2Idx, ElementSparseMask, ElementSparseIdx, ElementSparseCount>; | ||
| 206 | + // 处理单个tile内Q和K的matmul | ||
| 207 | + using L1TileShapeQK = Shape<Int<128>, Int<512>, Int<128>>; | ||
| 208 | + using L0TileShapeQK = Shape<Int<128>, Int<256>, Int<128>>; | ||
| 209 | + using DispatchPolicyQK = Gemm::MmadAtlasA5BsaQK; | ||
| 210 | + using TileCopyQK = Gemm::Tile::PackedTileCopyTlaToUB< | ||
| 211 | + ArchTag, ElementQ, LayoutQ, ElementK, LayoutK, ElementS, LayoutS, | ||
| 212 | + void, Gemm::Tile::CopyL0CToUBMode::NO_SPLIT, false, QKScaleGranularitySelector<GetQuantMode<ElementQ, ElementK, ElementV, OUTPODType>::value>::value>; | ||
| 213 | + using BlockMmadQK = Gemm::Block::BlockMmadTla< | ||
| 214 | + DispatchPolicyQK, L1TileShapeQK, L0TileShapeQK, ElementQ, ElementK, ElementS, void, TileCopyQK>; | ||
| 215 | + // online softmax | ||
| 216 | + using DispatchPolicyOnlineSoftmax = Epilogue::EpilogueOnlineSoftmaxBsa; | ||
| 217 | + using PType = Gemm::GemmType<ElementP, layout::zN>; | ||
| 218 | + using SType = Gemm::GemmType<ElementS, LayoutS>; | ||
| 219 | + using EpilogueOnlineSoftmax = Epilogue::Block::BlockEpilogue<DispatchPolicyOnlineSoftmax, PType, SType>; | ||
| 220 | + // 处理单个tile内P和Value的matmul | ||
| 221 | + using L1TileShapePV = Shape<Int<128>, Int<128>, Int<512>>; | ||
| 222 | + using L0TileShapePV = Shape<Int<128>, Int<128>, Int<256>>; | ||
| 223 | + using DispatchPolicyPV = Gemm::MmadAtlasA5BsaPV; | ||
| 224 | + using TileCopyPV = Gemm::Tile::PackedTileCopyTlaToUB< | ||
| 225 | + ArchTag, ElementP, LayoutPDummy, ElementV, LayoutV, ElementOTmp, LayoutOTmp, | ||
| 226 | + void, Gemm::Tile::CopyL0CToUBMode::SPLIT_M, false, PVScaleGranularitySelector<GetQuantMode<ElementQ, ElementK, ElementV, OUTPODType>::value>::value>; | ||
| 227 | + using BlockMmadPV = Gemm::Block::BlockMmadTla< | ||
| 228 | + DispatchPolicyPV, L1TileShapePV, L0TileShapePV, ElementP, ElementV, ElementOTmp, void, TileCopyPV>; | ||
| 229 | + // rescale O | ||
| 230 | + using DispatchPolicyRescaleO = Epilogue::EpilogueAtlasA5BsaRescaleO; | ||
| 231 | + using TileCopyRescaleO = Epilogue::Tile::TileCopyRescaleO< | ||
| 232 | + ArchTag, ElementO, LayoutO, LayoutOTmp>; | ||
| 233 | + using EpilogueRescaleO = Epilogue::Block::BlockEpilogue< | ||
| 234 | + DispatchPolicyRescaleO, ElementO, ElementOTmp, ElementS, TileCopyRescaleO, Arch::PositionL0C>; | ||
| 235 | + | ||
| 236 | + using BsaRegularKernelArch35 = BsaRegularKernelArch35< | ||
| 237 | + EpilogueMask2Idx, BlockMmadQK, EpilogueOnlineSoftmax, BlockMmadPV, EpilogueRescaleO, qFormat, kvFormat>; | ||
| 238 | + BsaKernelParamsArch35 params{q, k, v, mask, blockTables, query_scale, key_scale, value_scale, | ||
| 239 | + actualQseqlen, actualKvseqlen, blockSparseMask, o, workspace, tiling}; | ||
| 240 | + BsaRegularKernelArch35 bsaRegularKernelArch35; | ||
| 241 | + bsaRegularKernelArch35.template operator()<GetQuantMode<ElementQ, ElementK, ElementV, OUTPODType>::value>(params); | ||
| 242 | +} | ||
| 243 | + | ||
| @@ -0,0 +1,794 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file eagle_quant_block_sparse_attention_kernel.h | ||
| 13 | + * \brief Block Sparse Attention Kernel Implementation | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +using namespace NpuArch; | ||
| 22 | +using namespace RfaKenelCommon; | ||
| 23 | + | ||
| 24 | +namespace BlockSparse { | ||
| 25 | + /** | ||
| 26 | + * @brief Block Sparse Attention Inference Kernel | ||
| 27 | + * This kernel implements block sparse attention where attention is computed only on | ||
| 28 | + * selected KV blocks specified by selectIdx. This reduces computation for long sequences | ||
| 29 | + * by focusing on relevant tokens. | ||
| 30 | + * @tparam BlockMmadQK Block-level QK matmul module | ||
| 31 | + * @tparam BlockMmadPV Block-level PV matmul module | ||
| 32 | + * @tparam EpilogueOnlineSoftmax Online softmax epilogue | ||
| 33 | + * @tparam EpilogueRescaleO Output rescaling epilogue | ||
| 34 | + * @tparam PAGED_CACHE_FLAG Whether to use paged KV cache | ||
| 35 | + * @tparam QUERY_LAYOUT Query tensor layout (0=TND, 1=BNSD) | ||
| 36 | + * @tparam KV_CACHE_LAYOUT KV cache layout (0=TND, 1=BNSD) | ||
| 37 | + */ | ||
| 38 | + template < | ||
| 39 | + class BlockMmadQK, | ||
| 40 | + class BlockMmadPV, | ||
| 41 | + class EpilogueOnlineSoftmax, | ||
| 42 | + class EpilogueRescaleO, | ||
| 43 | + bool PAGED_CACHE_FLAG, | ||
| 44 | + uint32_t QUERY_LAYOUT, | ||
| 45 | + uint32_t KV_CACHE_LAYOUT> | ||
| 46 | + class EagleQuantBlockSparseAttentionKernel { | ||
| 47 | + public: | ||
| 48 | + using ArchTag = typename BlockMmadQK::ArchTag; | ||
| 49 | + using L1TileShape = typename BlockMmadQK::L1TileShape; | ||
| 50 | + using ElementQ = typename BlockMmadQK::ElementA; | ||
| 51 | + using LayoutQ = typename BlockMmadQK::LayoutA; | ||
| 52 | + using ElementK = typename BlockMmadQK::ElementB; | ||
| 53 | + using LayoutK = typename BlockMmadQK::LayoutB; | ||
| 54 | + using ElementS = typename BlockMmadQK::ElementC; | ||
| 55 | + using LayoutS = typename BlockMmadQK::LayoutC; | ||
| 56 | + | ||
| 57 | + using ElementP = typename BlockMmadPV::ElementA; | ||
| 58 | + using LayoutP = typename BlockMmadPV::LayoutA; | ||
| 59 | + | ||
| 60 | + using ElementV = typename BlockMmadPV::ElementB; | ||
| 61 | + using LayoutV = typename BlockMmadPV::LayoutB; | ||
| 62 | + | ||
| 63 | + using ElementMask = typename EpilogueOnlineSoftmax::ElementMask; | ||
| 64 | + | ||
| 65 | + using ElementO = typename EpilogueRescaleO::ElementOutput; | ||
| 66 | + using LayoutO = typename EpilogueRescaleO::LayoutOutput; | ||
| 67 | + | ||
| 68 | + using ElementOTmp = typename EpilogueRescaleO::ElementInput; | ||
| 69 | + using LayoutOTmp = typename EpilogueRescaleO::LayoutInput; | ||
| 70 | + | ||
| 71 | + using ElementLse = typename EpilogueRescaleO::ElementLse; | ||
| 72 | + using LayoutLse = typename EpilogueRescaleO::LayoutLse; | ||
| 73 | + | ||
| 74 | + using ElementUpdate = typename EpilogueRescaleO::ElementUpdate; | ||
| 75 | + using LayoutUpdate = typename EpilogueRescaleO::LayoutUpdate; | ||
| 76 | + | ||
| 77 | + static constexpr Epilogue::LseMode LSE_MODE = EpilogueRescaleO::LSE_MODE; | ||
| 78 | + static constexpr int32_t BASIC_BLOCK = 64; | ||
| 79 | + static constexpr uint32_t LS_UB_TENSOR_OFFSET = 0; | ||
| 80 | + static constexpr uint32_t MASK_PATTERN_HALF_OFFSET = BASIC_BLOCK * 2 + LS_UB_TENSOR_OFFSET; | ||
| 81 | + static constexpr uint32_t MASK_PATTERN_FLOAT_OFFSET = BASIC_BLOCK * 2 + MASK_PATTERN_HALF_OFFSET; | ||
| 82 | + static constexpr uint32_t MASK_BIT_OFFSET = BASIC_BLOCK * 4 + MASK_PATTERN_FLOAT_OFFSET; | ||
| 83 | + static constexpr uint32_t MASK_IDX_OFFSET = BASIC_BLOCK + MASK_BIT_OFFSET; | ||
| 84 | + static constexpr uint32_t SPARSE_IDX_OFFSET = BASIC_BLOCK * 4 + MASK_IDX_OFFSET; | ||
| 85 | + static constexpr uint32_t SELECT_NUM_IDX_OFFSET = BASIC_BLOCK * 4 + SPARSE_IDX_OFFSET; | ||
| 86 | + static constexpr uint32_t SYNC_OFFSET = BASIC_BLOCK * 4 + SELECT_NUM_IDX_OFFSET; | ||
| 87 | + | ||
| 88 | + __aicore__ inline | ||
| 89 | + EagleQuantBlockSparseAttentionKernel() {} | ||
| 90 | + | ||
| 91 | + __aicore__ inline void Mask2IdxAndCount(const AscendC::GlobalTensor<uint8_t> maskGM, | ||
| 92 | + AscendC::GlobalTensor<int32_t> selectIdxGM, | ||
| 93 | + AscendC::GlobalTensor<int32_t> selectNumGM) | ||
| 94 | + { | ||
| 95 | + static constexpr uint32_t PRE_ROW_TILE = 128; | ||
| 96 | + static constexpr uint32_t PRE_COL_TILE = 64; | ||
| 97 | + static constexpr uint32_t PRE_ELEM_NUM_PER_LOOP = PRE_ROW_TILE * PRE_COL_TILE; | ||
| 98 | + static constexpr uint32_t MASK_PAT_IN_UINT8 = 0; | ||
| 99 | + static constexpr uint32_t MASK_PAT_IN_FP16 = 2 * PRE_ELEM_NUM_PER_LOOP; | ||
| 100 | + static constexpr uint32_t MASK_PAT_IN_FP32 = 4 * PRE_ELEM_NUM_PER_LOOP; | ||
| 101 | + static constexpr uint32_t MASK_PAT_IN_BIT = 8 * PRE_ELEM_NUM_PER_LOOP; | ||
| 102 | + static constexpr uint32_t MASK_IDX = 9 * PRE_ELEM_NUM_PER_LOOP; | ||
| 103 | + static constexpr uint32_t RSVD_SPARSE_IDX = 13 * PRE_ELEM_NUM_PER_LOOP; | ||
| 104 | + static constexpr uint32_t RSVD_SPARSE_COUNT = 21 * PRE_ELEM_NUM_PER_LOOP; | ||
| 105 | + | ||
| 106 | + AscendC::LocalTensor<uint8_t> maskPatternUbLocal[2]; | ||
| 107 | + AscendC::LocalTensor<int32_t> selectNumIdxUbLocal[2]; | ||
| 108 | + AscendC::LocalTensor<uint8_t> maskPatternInBitUbLocal; | ||
| 109 | + AscendC::LocalTensor<uint32_t> maskPatternInBitUbLocalUint32; | ||
| 110 | + | ||
| 111 | + AscendC::LocalTensor<int32_t> maskIdxUbLocal; | ||
| 112 | + AscendC::LocalTensor<int32_t> sparseIdxUbLocal[2]; | ||
| 113 | + AscendC::LocalTensor<half> maskPatternHalfLocal; | ||
| 114 | + AscendC::LocalTensor<float> maskPatternFloatLocal; | ||
| 115 | + | ||
| 116 | + for (uint32_t i = 0; i < 2; i++) { | ||
| 117 | + maskPatternUbLocal[i] = resource.ubBuf.template GetBufferByByte<uint8_t>( | ||
| 118 | + MASK_PAT_IN_UINT8 + i * PRE_ELEM_NUM_PER_LOOP * sizeof(int8_t)); | ||
| 119 | + sparseIdxUbLocal[i] = resource.ubBuf.template GetBufferByByte<int32_t>( | ||
| 120 | + RSVD_SPARSE_IDX + i * PRE_ELEM_NUM_PER_LOOP * sizeof(int32_t)); | ||
| 121 | + selectNumIdxUbLocal[i] = resource.ubBuf.template GetBufferByByte<int32_t>( | ||
| 122 | + RSVD_SPARSE_COUNT + i * PRE_ROW_TILE * sizeof(int32_t)); | ||
| 123 | + } | ||
| 124 | + maskPatternHalfLocal = resource.ubBuf.template GetBufferByByte<half>(MASK_PAT_IN_FP16); | ||
| 125 | + maskPatternFloatLocal = resource.ubBuf.template GetBufferByByte<float>(MASK_PAT_IN_FP32); | ||
| 126 | + maskPatternInBitUbLocal = resource.ubBuf.template GetBufferByByte<uint8_t>(MASK_PAT_IN_BIT); | ||
| 127 | + maskPatternInBitUbLocalUint32 = resource.ubBuf.template GetBufferByByte<uint32_t>(MASK_PAT_IN_BIT); | ||
| 128 | + maskIdxUbLocal = resource.ubBuf.template GetBufferByByte<int32_t>(MASK_IDX); | ||
| 129 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(0); | ||
| 130 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(1); | ||
| 131 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(0); | ||
| 132 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(1); | ||
| 133 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(2); | ||
| 134 | + AscendC::SetFlag<AscendC::HardEvent::S_MTE3>(0); | ||
| 135 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(0); | ||
| 136 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(1); | ||
| 137 | + | ||
| 138 | + uint32_t subCoreIdx = AscendC::GetBlockIdx(); | ||
| 139 | + uint32_t curStartRowIdx = subCoreIdx * avgRowPerSubCore; | ||
| 140 | + uint32_t totalRowNumBlockMask = batch * qHeads * maxQBlockNum; | ||
| 141 | + uint32_t actDealtRow = (subCoreIdx == preActivateSubCoreNum - 1) ? | ||
| 142 | + (totalRowNumBlockMask - curStartRowIdx) : avgRowPerSubCore; | ||
| 143 | + if (subCoreIdx < preActivateSubCoreNum) { | ||
| 144 | + uint32_t rowLoop = CeilDiv(actDealtRow, PRE_ROW_TILE); | ||
| 145 | + uint32_t colLoop = CeilDiv(maxKvBlockNum, PRE_COL_TILE); | ||
| 146 | + uint32_t idxPingPongFlag = 0; | ||
| 147 | + uint32_t countPingPongFlag = 0; | ||
| 148 | + for (uint32_t i = 0; i < rowLoop; i++) { | ||
| 149 | + uint32_t curLoopRowOffset = i * PRE_ROW_TILE; | ||
| 150 | + int32_t actDealtRowCurLoop = (i == rowLoop - 1) ? (actDealtRow - curLoopRowOffset) : PRE_ROW_TILE; | ||
| 151 | + uint64_t rsvdCountPerRow[PRE_ROW_TILE] = {0}; | ||
| 152 | + uint64_t rsvdCountPerRowCurColLoop[PRE_ROW_TILE] = {0}; | ||
| 153 | + for (uint32_t j = 0; j < colLoop; j++) { | ||
| 154 | + uint32_t curLoopColOffset = j * PRE_COL_TILE; | ||
| 155 | + uint32_t actDealtColCurLoop = | ||
| 156 | + (j == colLoop - 1) ? (maxKvBlockNum - curLoopColOffset) : PRE_COL_TILE; | ||
| 157 | + uint32_t actDealtColCurLoop32 = CeilDiv(actDealtColCurLoop, 32) * 32; | ||
| 158 | + AscendC::CreateVecIndex(maskIdxUbLocal, static_cast<int32_t>(curLoopColOffset), PRE_COL_TILE); | ||
| 159 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 160 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(idxPingPongFlag); | ||
| 161 | + int32_t maskOffset = curStartRowIdx * maxKvBlockNum + | ||
| 162 | + curLoopRowOffset * maxKvBlockNum + curLoopColOffset; | ||
| 163 | + AscendC::DataCopyPad( | ||
| 164 | + maskPatternUbLocal[idxPingPongFlag], | ||
| 165 | + maskGM[maskOffset], | ||
| 166 | + AscendC::DataCopyExtParams( | ||
| 167 | + actDealtRowCurLoop, | ||
| 168 | + actDealtColCurLoop * sizeof(int8_t), | ||
| 169 | + (maxKvBlockNum - actDealtColCurLoop) * sizeof(int8_t), | ||
| 170 | + (PRE_COL_TILE - actDealtColCurLoop32) / 32, 0), | ||
| 171 | + AscendC::DataCopyPadExtParams<uint8_t>( | ||
| 172 | + true, 0, (actDealtColCurLoop32 - actDealtColCurLoop), 0)); | ||
| 173 | + | ||
| 174 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(0); | ||
| 175 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(0); | ||
| 176 | + AscendC::Cast( | ||
| 177 | + maskPatternHalfLocal, maskPatternUbLocal[idxPingPongFlag], | ||
| 178 | + AscendC::RoundMode::CAST_NONE, actDealtRowCurLoop * PRE_COL_TILE); | ||
| 179 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 180 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(idxPingPongFlag); | ||
| 181 | + AscendC::Cast( | ||
| 182 | + maskPatternFloatLocal, maskPatternHalfLocal, | ||
| 183 | + AscendC::RoundMode::CAST_NONE, actDealtRowCurLoop * PRE_COL_TILE); | ||
| 184 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 185 | + for (uint32_t k = 0; k < actDealtRowCurLoop; k++) { | ||
| 186 | + if (actDealtColCurLoop32 != PRE_COL_TILE) { | ||
| 187 | + AscendC::Duplicate(maskPatternFloatLocal[k * PRE_COL_TILE + actDealtColCurLoop32], | ||
| 188 | + (float)0, PRE_COL_TILE - actDealtColCurLoop32); | ||
| 189 | + } | ||
| 190 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 191 | + AscendC::CompareScalar( | ||
| 192 | + maskPatternInBitUbLocal[k * PRE_COL_TILE], | ||
| 193 | + maskPatternFloatLocal[k * PRE_COL_TILE], | ||
| 194 | + (float)1.0, AscendC::CMPMODE::GE, PRE_COL_TILE); | ||
| 195 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 196 | + if (k == 0) { | ||
| 197 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(idxPingPongFlag); | ||
| 198 | + } | ||
| 199 | + AscendC::GatherMask( | ||
| 200 | + sparseIdxUbLocal[idxPingPongFlag][k * PRE_COL_TILE], | ||
| 201 | + maskIdxUbLocal, | ||
| 202 | + maskPatternInBitUbLocalUint32[k * PRE_COL_TILE / 4], | ||
| 203 | + false, | ||
| 204 | + (uint32_t)0, {1, 1, 0, 0}, rsvdCountPerRowCurColLoop[k]); | ||
| 205 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(0); | ||
| 206 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(0); | ||
| 207 | + if (k == 0) { | ||
| 208 | + AscendC::WaitFlag<AscendC::HardEvent::S_MTE3>(0); | ||
| 209 | + } | ||
| 210 | + AscendC::DataCopyPad( | ||
| 211 | + selectIdxGM[curStartRowIdx * maxKvBlockNum + | ||
| 212 | + curLoopRowOffset * maxKvBlockNum + k * maxKvBlockNum + rsvdCountPerRow[k]], | ||
| 213 | + sparseIdxUbLocal[idxPingPongFlag][k * PRE_COL_TILE], | ||
| 214 | + AscendC::DataCopyExtParams( | ||
| 215 | + 1, rsvdCountPerRowCurColLoop[k] * sizeof(int32_t), 0, 0, 0)); | ||
| 216 | + if (k == actDealtRowCurLoop - 1) { | ||
| 217 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(idxPingPongFlag); | ||
| 218 | + } | ||
| 219 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(0); | ||
| 220 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(0); | ||
| 221 | + rsvdCountPerRow[k] += rsvdCountPerRowCurColLoop[k]; | ||
| 222 | + if (k == actDealtRowCurLoop - 1) { | ||
| 223 | + AscendC::SetFlag<AscendC::HardEvent::S_MTE3>(0); | ||
| 224 | + } | ||
| 225 | + } | ||
| 226 | + idxPingPongFlag = 1 - idxPingPongFlag; | ||
| 227 | + } | ||
| 228 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(countPingPongFlag); | ||
| 229 | + for (uint32_t k = 0; k < actDealtRowCurLoop; k++) { | ||
| 230 | + selectNumIdxUbLocal[countPingPongFlag].SetValue(k, static_cast<int32_t>(rsvdCountPerRow[k])); | ||
| 231 | + } | ||
| 232 | + AscendC::SetFlag<AscendC::HardEvent::S_MTE3>(countPingPongFlag + 2); | ||
| 233 | + AscendC::WaitFlag<AscendC::HardEvent::S_MTE3>(countPingPongFlag + 2); | ||
| 234 | + AscendC::DataCopyPad( | ||
| 235 | + selectNumGM[curStartRowIdx + curLoopRowOffset], | ||
| 236 | + selectNumIdxUbLocal[countPingPongFlag], | ||
| 237 | + AscendC::DataCopyExtParams(1, actDealtRowCurLoop * sizeof(int32_t), 0, 0, 0)); | ||
| 238 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_S>(countPingPongFlag); | ||
| 239 | + countPingPongFlag = 1 - countPingPongFlag; | ||
| 240 | + } | ||
| 241 | + } | ||
| 242 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(0); | ||
| 243 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(1); | ||
| 244 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(0); | ||
| 245 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(1); | ||
| 246 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(2); | ||
| 247 | + AscendC::WaitFlag<AscendC::HardEvent::S_MTE3>(0); | ||
| 248 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(0); | ||
| 249 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_S>(1); | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + __aicore__ inline void operator()(EagleQuantBlockSparseAttentionKernelParams const ¶ms) | ||
| 253 | + { | ||
| 254 | + __gm__ EagleQuantBlockSparseAttentionTilingData *blockSparseAttentionTilingData = | ||
| 255 | + reinterpret_cast<__gm__ EagleQuantBlockSparseAttentionTilingData *>(params.tiling); | ||
| 256 | + uint64_t mm1OutSize = blockSparseAttentionTilingData->mm1OutSize; | ||
| 257 | + uint64_t smOnlineOutSize = blockSparseAttentionTilingData->smOnlineOutSize; | ||
| 258 | + uint64_t mm2OutSize = blockSparseAttentionTilingData->mm2OutSize; | ||
| 259 | + uint64_t updateSize = blockSparseAttentionTilingData->updateSize; | ||
| 260 | + uint64_t selectNumIdxSize = blockSparseAttentionTilingData->selectNumIdxSize; | ||
| 261 | + uint64_t selectIdxSize = blockSparseAttentionTilingData->selectIdxSize; | ||
| 262 | + | ||
| 263 | + batch = blockSparseAttentionTilingData->batch; | ||
| 264 | + qHeads = blockSparseAttentionTilingData->numHeads; | ||
| 265 | + uint32_t kvHeads = blockSparseAttentionTilingData->kvHeads; | ||
| 266 | + | ||
| 267 | + uint32_t embed = blockSparseAttentionTilingData->embeddingSize; | ||
| 268 | + uint32_t pagedBlockSize = blockSparseAttentionTilingData->blockSize; | ||
| 269 | + uint32_t maxNumBlocksPerBatch = blockSparseAttentionTilingData->maxNumBlocksPerBatch; | ||
| 270 | + uint32_t firstBatchTaskNum = blockSparseAttentionTilingData->firstBatchTaskNum; | ||
| 271 | + uint32_t totalTaskNum = blockSparseAttentionTilingData->totalTaskNum; | ||
| 272 | + uint32_t maskType = blockSparseAttentionTilingData->maskType; | ||
| 273 | + ElementS scaleValue = static_cast<ElementS>(blockSparseAttentionTilingData->scaleValue); | ||
| 274 | + uint32_t totalQBlocks = blockSparseAttentionTilingData->totalQBlocks; | ||
| 275 | + maxKvBlockNum = blockSparseAttentionTilingData->maxKvBlockNum; | ||
| 276 | + uint32_t maxKvBlockNumPad = CeilDiv(maxKvBlockNum, 32) * 32; | ||
| 277 | + maxQBlockNum = blockSparseAttentionTilingData->maxQBlockNum; | ||
| 278 | + avgRowPerSubCore = blockSparseAttentionTilingData->avgRowNumPerSubCore; | ||
| 279 | + preActivateSubCoreNum = blockSparseAttentionTilingData->preActivateSubCoreNum; | ||
| 280 | + | ||
| 281 | + uint32_t qBlockX = blockSparseAttentionTilingData->blockShapeX; | ||
| 282 | + uint32_t qBlockY = blockSparseAttentionTilingData->blockShapeY; | ||
| 283 | + uint32_t qBlockNum = totalQBlocks / qBlockX; | ||
| 284 | + uint32_t qBlockInX = (qBlockX + BASIC_BLOCK_SIZE - 1) / BASIC_BLOCK_SIZE; | ||
| 285 | + uint32_t firstQBlockNum = blockSparseAttentionTilingData->firstQBlockNum; | ||
| 286 | + uint32_t maxQSeqlen = blockSparseAttentionTilingData->maxQSeqlen; | ||
| 287 | + uint32_t maxKvSeqlen = blockSparseAttentionTilingData->maxKvSeqlen; | ||
| 288 | + uint32_t useUniformQSeqlen = blockSparseAttentionTilingData->useUniformQSeqlen; | ||
| 289 | + uint32_t useUniformKvSeqlen = blockSparseAttentionTilingData->useUniformKvSeqlen; | ||
| 290 | + | ||
| 291 | + // Initialize global tensors | ||
| 292 | + AscendC::GlobalTensor<ElementQ> gQ; | ||
| 293 | + gQ.SetGlobalBuffer((__gm__ ElementQ *)params.q); | ||
| 294 | + AscendC::GlobalTensor<ElementK> gK; | ||
| 295 | + gK.SetGlobalBuffer((__gm__ ElementK *)params.k); | ||
| 296 | + AscendC::GlobalTensor<ElementK> gV; | ||
| 297 | + gV.SetGlobalBuffer((__gm__ ElementK *)params.v); | ||
| 298 | + AscendC::GlobalTensor<int32_t> gBlockTable; | ||
| 299 | + gBlockTable.SetGlobalBuffer((__gm__ int32_t *)(params.blockTables)); | ||
| 300 | + AscendC::GlobalTensor<int64_t> gActualQseqlen; | ||
| 301 | + gActualQseqlen.SetGlobalBuffer((__gm__ int64_t *)params.actualQseqlen); | ||
| 302 | + AscendC::GlobalTensor<int64_t> gActualKvseqlen; | ||
| 303 | + gActualKvseqlen.SetGlobalBuffer((__gm__ int64_t *)params.actualKvseqlen); | ||
| 304 | + AscendC::GlobalTensor<int32_t> gSelectIdx; | ||
| 305 | + gSelectIdx.SetGlobalBuffer((__gm__ int32_t *)(params.workspace + mm1OutSize + | ||
| 306 | + smOnlineOutSize + mm2OutSize + updateSize + selectNumIdxSize)); | ||
| 307 | + AscendC::GlobalTensor<int32_t> gSelectNumIdx; | ||
| 308 | + gSelectNumIdx.SetGlobalBuffer((__gm__ int32_t *)(params.workspace + mm1OutSize + | ||
| 309 | + smOnlineOutSize + mm2OutSize + updateSize)); | ||
| 310 | + AscendC::GlobalTensor<uint8_t> gBlockSparseMask; | ||
| 311 | + gBlockSparseMask.SetGlobalBuffer((__gm__ uint8_t *)params.blockSparseMask); | ||
| 312 | + AscendC::GlobalTensor<ElementO> gO; | ||
| 313 | + gO.SetGlobalBuffer((__gm__ ElementO *)params.o); | ||
| 314 | + AscendC::GlobalTensor<ElementLse> gLse; | ||
| 315 | + gLse.SetGlobalBuffer((__gm__ ElementLse *)params.lse); | ||
| 316 | + AscendC::GlobalTensor<ElementS> gS; | ||
| 317 | + gS.SetGlobalBuffer((__gm__ ElementS *)params.workspace); | ||
| 318 | + AscendC::GlobalTensor<ElementP> gP; | ||
| 319 | + gP.SetGlobalBuffer((__gm__ ElementP *)(params.workspace + mm1OutSize)); | ||
| 320 | + AscendC::GlobalTensor<ElementOTmp> gOTmp; | ||
| 321 | + gOTmp.SetGlobalBuffer((__gm__ ElementOTmp *)(params.workspace + mm1OutSize + smOnlineOutSize)); | ||
| 322 | + AscendC::GlobalTensor<ElementOTmp> gOUpdate; | ||
| 323 | + gOUpdate.SetGlobalBuffer((__gm__ ElementOTmp *)(params.workspace + mm1OutSize + | ||
| 324 | + smOnlineOutSize + mm2OutSize)); | ||
| 325 | + | ||
| 326 | + uint32_t coreIdx = AscendC::GetBlockIdx(); | ||
| 327 | + uint32_t coreNum = AscendC::GetBlockNum(); | ||
| 328 | + | ||
| 329 | + Mask2IdxAndCount(gBlockSparseMask, gSelectIdx, gSelectNumIdx); | ||
| 330 | + | ||
| 331 | + resource.pipe.Reset(); | ||
| 332 | + AscendC::SyncAll<false>(); | ||
| 333 | + | ||
| 334 | + | ||
| 335 | + // Initialize hardware events for cube core | ||
| 336 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID0); | ||
| 337 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID1); | ||
| 338 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID2); | ||
| 339 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID3); | ||
| 340 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID4); | ||
| 341 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID5); | ||
| 342 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID6); | ||
| 343 | + AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID7); | ||
| 344 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID0); | ||
| 345 | + AscendC::SetFlag<AscendC::HardEvent::FIX_M>(EVENT_ID1); | ||
| 346 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 347 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID1); | ||
| 348 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID2); | ||
| 349 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID3); | ||
| 350 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID4); | ||
| 351 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID5); | ||
| 352 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID6); | ||
| 353 | + AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID7); | ||
| 354 | + | ||
| 355 | + static constexpr uint32_t L1_QK_SIZE = | ||
| 356 | + BlockMmadQK::L1TileShape::M * BlockMmadQK::L1TileShape::K * sizeof(ElementQ) + | ||
| 357 | + BlockMmadQK::L1TileShape::N * BlockMmadQK::L1TileShape::K * sizeof(ElementK) * 2; | ||
| 358 | + BlockMmadQK blockMmadQK(resource); | ||
| 359 | + BlockMmadPV blockMmadPV(resource, L1_QK_SIZE); | ||
| 360 | + | ||
| 361 | + | ||
| 362 | + | ||
| 363 | + // Initialize hardware events for vector core | ||
| 364 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID0); | ||
| 365 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID1); | ||
| 366 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 367 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID2); | ||
| 368 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID3); | ||
| 369 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID4); | ||
| 370 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID5); | ||
| 371 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID6); | ||
| 372 | + | ||
| 373 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 374 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID1); | ||
| 375 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID3); | ||
| 376 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID2); | ||
| 377 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID2); | ||
| 378 | + | ||
| 379 | + EpilogueOnlineSoftmax epilogueOnlineSoftmax(resource, scaleValue); | ||
| 380 | + EpilogueRescaleO epilogueRescaleO(resource); | ||
| 381 | + | ||
| 382 | + coreIdx = AscendC::GetBlockIdx() / AscendC::GetSubBlockNum(); | ||
| 383 | + uint32_t bn = AscendC::GetSubBlockNum(); | ||
| 384 | + | ||
| 385 | + // Calculate strides based on layout (compile-time optimization) | ||
| 386 | + // For TND: [T, N, D], stride = N * D | ||
| 387 | + // For BNSD: [B, N, S, D], strideB = N * S * D, strideN = S * D, strideS = D | ||
| 388 | + uint64_t strideQO = 0; | ||
| 389 | + uint64_t strideKV = 0; | ||
| 390 | + uint64_t strideQOB = 0; // BNSD batch stride for Q | ||
| 391 | + uint64_t strideQON = 0; // BNSD head stride for Q | ||
| 392 | + uint64_t strideQOS = 0; // BNSD seq stride for Q | ||
| 393 | + uint64_t strideKVB = 0; // BNSD batch stride for KV | ||
| 394 | + uint64_t strideKVN = 0; // BNSD head stride for KV | ||
| 395 | + uint64_t strideKVS = 0; // BNSD seq stride for KV | ||
| 396 | + | ||
| 397 | + if constexpr (QUERY_LAYOUT == 1) { // BNSD_Q | ||
| 398 | + // BNSD: [B, N, S, D] | ||
| 399 | + // strideB = N * S * D, strideN = S * D, strideS = D | ||
| 400 | + // maxQSeqlen is the third dimension (S) of query shape, set in tiling | ||
| 401 | + strideQOB = qHeads * maxQSeqlen * embed; // batch stride | ||
| 402 | + strideQON = maxQSeqlen * embed; // head stride | ||
| 403 | + strideQOS = embed; // seq stride | ||
| 404 | + } else { | ||
| 405 | + // TND: [T, N, D] | ||
| 406 | + strideQO = qHeads * embed; | ||
| 407 | + } | ||
| 408 | + | ||
| 409 | + if constexpr (KV_CACHE_LAYOUT == 1) { // BNSD | ||
| 410 | + // BNSD: [B, N, S, D] | ||
| 411 | + // maxKvSeqlen is the third dimension (S) of value shape, set in tiling | ||
| 412 | + strideKVB = kvHeads * maxKvSeqlen * embed; // batch stride | ||
| 413 | + strideKVN = maxKvSeqlen * embed; // head stride | ||
| 414 | + strideKVS = embed; // seq stride | ||
| 415 | + } else { | ||
| 416 | + // TND: [T, N, D] | ||
| 417 | + strideKV = kvHeads * embed; | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + uint32_t embedRound = AlignUp<uint32_t>(embed, BLOCK_SIZE); | ||
| 421 | + uint32_t groupSize = qHeads / kvHeads; | ||
| 422 | + | ||
| 423 | + uint64_t qBOffset = 0; | ||
| 424 | + uint64_t kBOffset = 0; | ||
| 425 | + uint64_t vBOffset = 0; | ||
| 426 | + uint64_t oBOffset = 0; | ||
| 427 | + uint64_t blockBOffset = 0; | ||
| 428 | + uint64_t lseBOffset = 0; | ||
| 429 | + | ||
| 430 | + uint32_t preTotalTaskNum = 0; | ||
| 431 | + uint32_t preTotalQBlockNum = 0; | ||
| 432 | + uint32_t curBatch = 0; | ||
| 433 | + // 根据useUniformQSeqlen标志位决定使用actualSeqLengths数组还是maxQSeqlen | ||
| 434 | + uint32_t qSeqlen = useUniformQSeqlen ? maxQSeqlen : | ||
| 435 | + static_cast<uint32_t>(static_cast<int64_t>(gActualQseqlen.GetValue(curBatch))); | ||
| 436 | + // 根据useUniformKvSeqlen标志位决定使用actualSeqLengthsKv数组还是maxKvSeqlen | ||
| 437 | + uint32_t kvSeqlen = useUniformKvSeqlen ? maxKvSeqlen : | ||
| 438 | + static_cast<uint32_t>(static_cast<int64_t>(gActualKvseqlen.GetValue(curBatch))); | ||
| 439 | + uint32_t curQNBlockTile = GetQNBlockTile(qSeqlen, groupSize); | ||
| 440 | + uint32_t qNBlockNumPerGroup = curQNBlockTile == 0 ? 1 : (groupSize + curQNBlockTile - 1) / curQNBlockTile; | ||
| 441 | + uint32_t curQNBlockNum = qNBlockNumPerGroup * kvHeads; | ||
| 442 | + uint32_t curQSBlockTile = GetQSBlockTile(kvSeqlen); | ||
| 443 | + uint32_t curQSBlockNum = GetQBlocks(qSeqlen, qBlockX); | ||
| 444 | + uint32_t curTotalTaskNum = firstBatchTaskNum; | ||
| 445 | + uint32_t curQXBlockNum = (qSeqlen + qBlockX - 1) / qBlockX; | ||
| 446 | + uint32_t curTotalQBlockNum = firstQBlockNum; | ||
| 447 | + | ||
| 448 | + // Go through each task | ||
| 449 | + for (uint32_t taskIdx = coreIdx; taskIdx < totalTaskNum; taskIdx += uint32_t(coreNum)) { | ||
| 450 | + while (taskIdx >= curTotalTaskNum) { | ||
| 451 | + ++curBatch; | ||
| 452 | + preTotalTaskNum = curTotalTaskNum; | ||
| 453 | + preTotalQBlockNum = curTotalQBlockNum; | ||
| 454 | + | ||
| 455 | + // Update offsets based on layout (compile-time optimization) | ||
| 456 | + if constexpr (QUERY_LAYOUT == 1) { // BNSD_Q | ||
| 457 | + // BNSD: [B, N, S, D], offset = batch * strideB | ||
| 458 | + qBOffset = curBatch * strideQOB; | ||
| 459 | + oBOffset = curBatch * strideQOB; | ||
| 460 | + lseBOffset = curBatch * qHeads * maxQSeqlen; | ||
| 461 | + } else { | ||
| 462 | + // TND | ||
| 463 | + qBOffset += qSeqlen * strideQO; | ||
| 464 | + oBOffset += qSeqlen * strideQO; | ||
| 465 | + lseBOffset += qSeqlen * qHeads; | ||
| 466 | + } | ||
| 467 | + | ||
| 468 | + if constexpr (!PAGED_CACHE_FLAG) { | ||
| 469 | + if constexpr (KV_CACHE_LAYOUT == 1) { // BNSD | ||
| 470 | + // BNSD: [B, N, S, D], offset = batch * strideB | ||
| 471 | + kBOffset = curBatch * strideKVB; | ||
| 472 | + vBOffset = curBatch * strideKVB; | ||
| 473 | + } else { | ||
| 474 | + // TND | ||
| 475 | + kBOffset += kvSeqlen * strideKV; | ||
| 476 | + vBOffset += kvSeqlen * strideKV; | ||
| 477 | + } | ||
| 478 | + } else { | ||
| 479 | + blockBOffset += maxNumBlocksPerBatch; | ||
| 480 | + } | ||
| 481 | + // 根据useUniformQSeqlen标志位决定使用actualSeqLengths数组还是maxQSeqlen | ||
| 482 | + qSeqlen = useUniformQSeqlen ? maxQSeqlen : | ||
| 483 | + static_cast<uint32_t>(static_cast<int64_t>(gActualQseqlen.GetValue(curBatch))); | ||
| 484 | + // 根据useUniformKvSeqlen标志位决定使用actualSeqLengthsKv数组还是maxKvSeqlen | ||
| 485 | + kvSeqlen = useUniformKvSeqlen ? maxKvSeqlen : | ||
| 486 | + static_cast<uint32_t>(static_cast<int64_t>(gActualKvseqlen.GetValue(curBatch))); | ||
| 487 | + curQNBlockTile = GetQNBlockTile(qSeqlen, groupSize); | ||
| 488 | + qNBlockNumPerGroup = curQNBlockTile == 0 ? 1 : (groupSize + curQNBlockTile - 1) / curQNBlockTile; | ||
| 489 | + curQNBlockNum = qNBlockNumPerGroup * kvHeads; | ||
| 490 | + curQSBlockTile = GetQSBlockTile(kvSeqlen); | ||
| 491 | + curQSBlockNum = GetQBlocks(qSeqlen, qBlockX); | ||
| 492 | + curTotalTaskNum += curQNBlockNum * curQSBlockNum; | ||
| 493 | + curQXBlockNum = (qSeqlen + qBlockX - 1) / qBlockX; | ||
| 494 | + curTotalQBlockNum += qHeads * curQXBlockNum; | ||
| 495 | + } | ||
| 496 | + | ||
| 497 | + // Q task splitting按照[qNBlockNum, qHead] | ||
| 498 | + uint32_t taskIdxCurBatch = taskIdx - preTotalTaskNum; | ||
| 499 | + uint32_t qSBlockIdx = taskIdxCurBatch / curQNBlockNum; | ||
| 500 | + uint32_t qXIdx = qSBlockIdx / qBlockInX; | ||
| 501 | + uint32_t qXInnerIdx = qSBlockIdx - qXIdx * qBlockInX; | ||
| 502 | + uint32_t qNBlockIdx = taskIdxCurBatch - qSBlockIdx * curQNBlockNum; | ||
| 503 | + uint32_t qNBlockIdxCurGroup = qNBlockIdx % qNBlockNumPerGroup; | ||
| 504 | + uint32_t xBlockNum = qSeqlen / qBlockX; | ||
| 505 | + uint32_t xTailNum = qSeqlen - xBlockNum * qBlockX; | ||
| 506 | + | ||
| 507 | + uint32_t kvHeadIdx = qNBlockIdx / qNBlockNumPerGroup; | ||
| 508 | + uint32_t qHeadIdx = kvHeadIdx * groupSize + qNBlockIdxCurGroup * curQNBlockTile; | ||
| 509 | + | ||
| 510 | + uint32_t curSelectIdx = curBatch * qHeads * maxQBlockNum + qHeadIdx * maxQBlockNum + qXIdx; | ||
| 511 | + uint32_t curSelectNum = static_cast<uint32_t>(gSelectNumIdx.GetValue(curSelectIdx)); | ||
| 512 | + if (curSelectNum == 0) { | ||
| 513 | + continue; | ||
| 514 | + } | ||
| 515 | + uint32_t lastSelectIdx = static_cast<int32_t>( | ||
| 516 | + gSelectIdx.GetValue(curSelectIdx * maxKvBlockNum + curSelectNum - 1)); | ||
| 517 | + uint32_t kvYBlockNum = (kvSeqlen + qBlockY - 1) / qBlockY; // CeilDiv | ||
| 518 | + uint32_t curKvSeqLen = (lastSelectIdx == kvYBlockNum - 1 && kvSeqlen % qBlockY != 0) ? | ||
| 519 | + qBlockY * (curSelectNum - 1) + kvSeqlen % qBlockY : qBlockY * curSelectNum; | ||
| 520 | + // Calculate offsets based on layout (compile-time optimization) | ||
| 521 | + uint64_t gmOffsetQ = 0; | ||
| 522 | + uint64_t gmOffsetK = 0; | ||
| 523 | + uint64_t gmOffsetV = 0; | ||
| 524 | + uint64_t gmOffsetO = 0; | ||
| 525 | + uint64_t gmOffsetLse = 0; | ||
| 526 | + if constexpr (QUERY_LAYOUT == 1) { // BNSD_Q: [B, N, S, D] | ||
| 527 | + // offset = batch * strideB + head * strideN + seq * strideS | ||
| 528 | + uint32_t qSeqOffset = qXIdx * qBlockX + qXInnerIdx * BASIC_BLOCK_SIZE; | ||
| 529 | + gmOffsetQ = qBOffset + qHeadIdx * strideQON + qSeqOffset * strideQOS; | ||
| 530 | + gmOffsetO = oBOffset + qHeadIdx * strideQON + qSeqOffset * strideQOS; | ||
| 531 | + // LSE format: [B, N, S] - strideN = maxQSeqlen | ||
| 532 | + gmOffsetLse = lseBOffset + qHeadIdx * maxQSeqlen + qSeqOffset; | ||
| 533 | + } else { | ||
| 534 | + // TND: [T, N, D] | ||
| 535 | + uint32_t qSeqOffset = qXIdx * qBlockX + qXInnerIdx * BASIC_BLOCK_SIZE; | ||
| 536 | + gmOffsetQ = qBOffset + qSeqOffset * strideQO + qHeadIdx * embed; | ||
| 537 | + gmOffsetO = oBOffset + qSeqOffset * strideQO + qHeadIdx * embed; | ||
| 538 | + // LSE format: [T, N] - same as Q/O but without D dimension | ||
| 539 | + gmOffsetLse = lseBOffset + qSeqOffset * qHeads + qHeadIdx; | ||
| 540 | + } | ||
| 541 | + | ||
| 542 | + if constexpr (KV_CACHE_LAYOUT == 1) { // BNSD: [B, N, S, D] | ||
| 543 | + // offset = batch * strideB + head * strideN | ||
| 544 | + // seq offset will be handled in blockMmadQK/blockMmadPV based on selectIdx | ||
| 545 | + gmOffsetK = kBOffset + kvHeadIdx * strideKVN; | ||
| 546 | + gmOffsetV = vBOffset + kvHeadIdx * strideKVN; | ||
| 547 | + } else { | ||
| 548 | + // TND: [T, N, D] | ||
| 549 | + gmOffsetK = kBOffset + kvHeadIdx * embed; | ||
| 550 | + gmOffsetV = vBOffset + kvHeadIdx * embed; | ||
| 551 | + } | ||
| 552 | + | ||
| 553 | + uint32_t qSBlockSize = (qXIdx == xBlockNum) ? | ||
| 554 | + (qXInnerIdx == xTailNum / curQSBlockTile ? | ||
| 555 | + xTailNum - qXInnerIdx * curQSBlockTile : curQSBlockTile) : | ||
| 556 | + ((qXInnerIdx == qBlockInX - 1) ? qBlockX - qXInnerIdx * curQSBlockTile : curQSBlockTile); | ||
| 557 | + | ||
| 558 | + uint32_t qNBlockSize = (qNBlockIdxCurGroup == (qNBlockNumPerGroup - 1)) ? | ||
| 559 | + (groupSize - qNBlockIdxCurGroup * curQNBlockTile) : curQNBlockTile; | ||
| 560 | + uint32_t rowNum = qSBlockSize * qNBlockSize; | ||
| 561 | + uint32_t rowNumRound = AlignUp<uint32_t>(rowNum, BLOCK_SIZE); | ||
| 562 | + | ||
| 563 | + uint32_t noSkipKvS = curKvSeqLen; | ||
| 564 | + uint32_t kvSLoopNumTotal = (noSkipKvS + pagedBlockSize - 1) / pagedBlockSize; // CeilDiv | ||
| 565 | + | ||
| 566 | + uint32_t blockStackNum = MAX_KV_STACK_LEN / pagedBlockSize; | ||
| 567 | + uint32_t stackSeqTile; | ||
| 568 | + uint32_t stackSeqTilePad = blockStackNum * pagedBlockSize; | ||
| 569 | + uint32_t preKVNum = PRE_LAUNCH * blockStackNum; | ||
| 570 | + int32_t stackSeqCount = 0; | ||
| 571 | + | ||
| 572 | + | ||
| 573 | + LayoutQ layoutQTemp(rowNum, embed); | ||
| 574 | + // For BNSD format, use strideKVS; for TND, use strideKV (compile-time) | ||
| 575 | + uint64_t actualStrideKV = 0; | ||
| 576 | + if constexpr (KV_CACHE_LAYOUT == 1) { | ||
| 577 | + actualStrideKV = strideKVS; | ||
| 578 | + } else { | ||
| 579 | + actualStrideKV = strideKV; | ||
| 580 | + } | ||
| 581 | + LayoutK layoutKTemp(actualStrideKV, blockStackNum * pagedBlockSize); | ||
| 582 | + LayoutV layoutVTemp(blockStackNum * pagedBlockSize, actualStrideKV); | ||
| 583 | + // Pass correct Q stride based on data format | ||
| 584 | + uint64_t qGmStride = 0; | ||
| 585 | + if constexpr (QUERY_LAYOUT == 1) { // BNSD: [B, N, S, D] | ||
| 586 | + qGmStride = strideQOS; // embed | ||
| 587 | + } else { // TND: [T, N, D] | ||
| 588 | + qGmStride = strideQO; // qHeads * embed | ||
| 589 | + } | ||
| 590 | + blockMmadQK.loadQGM(gQ[gmOffsetQ], layoutQTemp, rowNum, qNBlockSize, qGmStride); | ||
| 591 | + | ||
| 592 | + // Main computation loop: QK matmul -> Softmax -> PV matmul | ||
| 593 | + for (uint32_t kvSIdx = 0; kvSIdx < kvSLoopNumTotal + preKVNum; kvSIdx += blockStackNum) { | ||
| 594 | + // Stage 1: QK matmul (computed on CUBE core) | ||
| 595 | + if (kvSIdx < kvSLoopNumTotal) { | ||
| 596 | + stackSeqTile = noSkipKvS - kvSIdx * pagedBlockSize; | ||
| 597 | + if (stackSeqTile >= pagedBlockSize * blockStackNum) { | ||
| 598 | + stackSeqTile = pagedBlockSize * blockStackNum; | ||
| 599 | + } | ||
| 600 | + uint32_t curStackTileMod = stackSeqCount % (PRE_LAUNCH + 1); | ||
| 601 | + uint64_t gmOffsetS = coreIdx * WORKSPACE_BLOCK_SIZE_DB * (PRE_LAUNCH + 1) + | ||
| 602 | + curStackTileMod * WORKSPACE_BLOCK_SIZE_DB; | ||
| 603 | + GemmCoord actualBlockShapeQK{rowNum, stackSeqTile, embed}; | ||
| 604 | + LayoutS layOutS(rowNum, stackSeqTile, stackSeqTilePad); | ||
| 605 | + | ||
| 606 | + // For BNSD format, pass strideKVS; for TND, pass strideKV (compile-time) | ||
| 607 | + uint64_t actualStrideKVForQK = 0; | ||
| 608 | + if constexpr (KV_CACHE_LAYOUT == 1) { | ||
| 609 | + actualStrideKVForQK = strideKVS; | ||
| 610 | + } else { | ||
| 611 | + actualStrideKVForQK = strideKV; | ||
| 612 | + } | ||
| 613 | + blockMmadQK(gQ[gmOffsetQ], | ||
| 614 | + gK[gmOffsetK], | ||
| 615 | + gS[gmOffsetS], | ||
| 616 | + gBlockTable[blockBOffset], | ||
| 617 | + gSelectIdx[curSelectIdx * maxKvBlockNum], | ||
| 618 | + layoutQTemp, | ||
| 619 | + layoutKTemp, | ||
| 620 | + layOutS, | ||
| 621 | + actualBlockShapeQK, | ||
| 622 | + kvSIdx, | ||
| 623 | + kvSLoopNumTotal, | ||
| 624 | + pagedBlockSize, | ||
| 625 | + actualStrideKVForQK, | ||
| 626 | + qBlockY, | ||
| 627 | + curSelectNum, | ||
| 628 | + kvYBlockNum, | ||
| 629 | + kvSeqlen); | ||
| 630 | + NpuArch::Arch::CrossCoreSetFlag<0x2, PIPE_FIX>(qkReady); | ||
| 631 | + | ||
| 632 | + | ||
| 633 | + // Stage 2: Online softmax (computed on VECTOR core) | ||
| 634 | + LayoutP layOutP(rowNum, stackSeqTile, stackSeqTilePad); | ||
| 635 | + uint64_t gmOffsetP = gmOffsetS; | ||
| 636 | + | ||
| 637 | + NpuArch::Arch::CrossCoreWaitFlag(qkReady); | ||
| 638 | + // online softmax | ||
| 639 | + epilogueOnlineSoftmax(gP[gmOffsetP], | ||
| 640 | + gS[gmOffsetS], | ||
| 641 | + layOutP, | ||
| 642 | + layOutS, | ||
| 643 | + actualBlockShapeQK, | ||
| 644 | + (stackSeqCount == 0), | ||
| 645 | + 0, | ||
| 646 | + qSBlockSize, | ||
| 647 | + qNBlockSize, | ||
| 648 | + curStackTileMod, | ||
| 649 | + softmaxReady); | ||
| 650 | + | ||
| 651 | + } | ||
| 652 | + // Stage 3: PV matmul and output rescaling | ||
| 653 | + if (kvSIdx >= preKVNum) { | ||
| 654 | + uint32_t nowkvSIdx = kvSIdx - preKVNum; | ||
| 655 | + stackSeqTile = noSkipKvS - nowkvSIdx * pagedBlockSize; | ||
| 656 | + if (stackSeqTile >= pagedBlockSize * blockStackNum) { | ||
| 657 | + stackSeqTile = pagedBlockSize * blockStackNum; | ||
| 658 | + } | ||
| 659 | + uint32_t curStackTileMod = (stackSeqCount - PRE_LAUNCH) % (PRE_LAUNCH + 1); | ||
| 660 | + uint64_t gmOffsetOTmp = coreIdx * WORKSPACE_BLOCK_SIZE_DB * (PRE_LAUNCH + 1) + | ||
| 661 | + curStackTileMod * WORKSPACE_BLOCK_SIZE_DB; | ||
| 662 | + GemmCoord actualBlockShapePV{rowNum, embed, stackSeqTile}; | ||
| 663 | + LayoutOTmp layoutOTmp(rowNum, embed, embedRound); | ||
| 664 | + | ||
| 665 | + LayoutP layoutPTemp(rowNum, stackSeqTile, stackSeqTilePad); | ||
| 666 | + uint64_t gmOffsetP = coreIdx * WORKSPACE_BLOCK_SIZE_DB * (PRE_LAUNCH + 1) + | ||
| 667 | + curStackTileMod * WORKSPACE_BLOCK_SIZE_DB; | ||
| 668 | + // For BNSD format, pass strideKVS; for TND, pass strideKV (compile-time) | ||
| 669 | + uint64_t actualStrideKVForPV = 0; | ||
| 670 | + if constexpr (KV_CACHE_LAYOUT == 1) { | ||
| 671 | + actualStrideKVForPV = strideKVS; | ||
| 672 | + } else { | ||
| 673 | + actualStrideKVForPV = strideKV; | ||
| 674 | + } | ||
| 675 | + blockMmadPV(gP[gmOffsetP], | ||
| 676 | + gV[gmOffsetV], | ||
| 677 | + gOTmp[gmOffsetOTmp], | ||
| 678 | + gBlockTable[blockBOffset], | ||
| 679 | + gSelectIdx[curSelectIdx * maxKvBlockNum], | ||
| 680 | + layoutPTemp, | ||
| 681 | + layoutVTemp, | ||
| 682 | + layoutOTmp, | ||
| 683 | + actualBlockShapePV, | ||
| 684 | + nowkvSIdx, | ||
| 685 | + kvSLoopNumTotal, | ||
| 686 | + pagedBlockSize, | ||
| 687 | + kvSeqlen, | ||
| 688 | + actualStrideKVForPV, | ||
| 689 | + blockStackNum, | ||
| 690 | + softmaxReady, | ||
| 691 | + qBlockY, | ||
| 692 | + curSelectNum, | ||
| 693 | + kvYBlockNum); | ||
| 694 | + NpuArch::Arch::CrossCoreSetFlag<0x2, PIPE_FIX>(pvReady); | ||
| 695 | + | ||
| 696 | + | ||
| 697 | + // Setup layoutO based on data format | ||
| 698 | + LayoutO layoutO; | ||
| 699 | + LayoutLse layoutLse; | ||
| 700 | + if constexpr (QUERY_LAYOUT == 1) { // BNSD: [B, N, S, D] | ||
| 701 | + // BNSD format: stride[0] = embed (strideQOS) | ||
| 702 | + layoutO = LayoutO(qSeqlen, embed); | ||
| 703 | + layoutLse = LayoutLse(qSeqlen, 1); | ||
| 704 | + } else { // TND: [T, N, D] | ||
| 705 | + // TND format: stride[0] = qHeads * embed (strideQO) | ||
| 706 | + layoutO = LayoutO(qSeqlen, qHeads * embed); | ||
| 707 | + layoutLse = LayoutLse(qSeqlen, qHeads); | ||
| 708 | + } | ||
| 709 | + LayoutUpdate layoutUpdate(rowNum, embed, embedRound); | ||
| 710 | + uint64_t gmOffsetUpdate = (uint64_t)(coreIdx * WORKSPACE_BLOCK_SIZE_DB); | ||
| 711 | + | ||
| 712 | + NpuArch::Arch::CrossCoreWaitFlag(pvReady); | ||
| 713 | + // rescale O | ||
| 714 | + epilogueRescaleO( | ||
| 715 | + gO[gmOffsetO], | ||
| 716 | + gOTmp[gmOffsetOTmp], | ||
| 717 | + gOUpdate[gmOffsetUpdate], | ||
| 718 | + gLse[gmOffsetLse], | ||
| 719 | + layoutO, | ||
| 720 | + layoutOTmp, | ||
| 721 | + layoutUpdate, | ||
| 722 | + layoutLse, | ||
| 723 | + actualBlockShapePV, | ||
| 724 | + qSBlockSize, | ||
| 725 | + qNBlockSize, | ||
| 726 | + (stackSeqCount - PRE_LAUNCH == 0), | ||
| 727 | + nowkvSIdx + blockStackNum >= kvSLoopNumTotal, | ||
| 728 | + curStackTileMod); | ||
| 729 | + | ||
| 730 | + } | ||
| 731 | + stackSeqCount++; | ||
| 732 | + } | ||
| 733 | + } | ||
| 734 | + | ||
| 735 | + // Wait for all CUBE core events | ||
| 736 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID0); | ||
| 737 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID1); | ||
| 738 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID2); | ||
| 739 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID3); | ||
| 740 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID4); | ||
| 741 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID5); | ||
| 742 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID6); | ||
| 743 | + AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(EVENT_ID7); | ||
| 744 | + | ||
| 745 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID0); | ||
| 746 | + AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(EVENT_ID1); | ||
| 747 | + | ||
| 748 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID0); | ||
| 749 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID1); | ||
| 750 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID2); | ||
| 751 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID3); | ||
| 752 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID4); | ||
| 753 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID5); | ||
| 754 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID6); | ||
| 755 | + AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(EVENT_ID7); | ||
| 756 | + | ||
| 757 | + | ||
| 758 | + // Wait for all VECTOR core events | ||
| 759 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID2); | ||
| 760 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID3); | ||
| 761 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID4); | ||
| 762 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID5); | ||
| 763 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(EVENT_ID6); | ||
| 764 | + | ||
| 765 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID0); | ||
| 766 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID1); | ||
| 767 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID2); | ||
| 768 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_V>(EVENT_ID4); | ||
| 769 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID0); | ||
| 770 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID1); | ||
| 771 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID2); | ||
| 772 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(EVENT_ID3); | ||
| 773 | + | ||
| 774 | + AscendC::PipeBarrier<PIPE_ALL>(); | ||
| 775 | + } | ||
| 776 | + | ||
| 777 | + private: | ||
| 778 | + NpuArch::Arch::Resource<ArchTag> resource; | ||
| 779 | + NpuArch::Arch::CrossCoreFlag qkReady{QK_READY_ID}; | ||
| 780 | + NpuArch::Arch::CrossCoreFlag softmaxReady{SOFTMAX_READY_ID}; | ||
| 781 | + NpuArch::Arch::CrossCoreFlag pvReady{PV_READY_ID}; | ||
| 782 | + | ||
| 783 | + uint32_t batch{0}; | ||
| 784 | + uint32_t qHeads{0}; | ||
| 785 | + uint32_t maxQBlockNum{0}; | ||
| 786 | + uint32_t maxKvBlockNum{0}; | ||
| 787 | + uint32_t avgRowPerSubCore{0}; | ||
| 788 | + uint32_t preActivateSubCoreNum{0}; | ||
| 789 | + }; | ||
| 790 | + | ||
| 791 | +} // namespace BlockSparse | ||
| 792 | + | ||
| 793 | + | ||
| 794 | + | ||
Acsrc/ops/eagle_quant_block_sparse_attention/op_kernel/eagle_quant_block_sparse_attention_tilingkey.h+83-0
| @@ -0,0 +1,83 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * EagleQuantBlockSparseAttention TilingKey 定义 | ||
| 16 | + * | ||
| 17 | + * TilingKey编码规则 (64-bit): | ||
| 18 | + * 位域: AAAABBBBCCCCDDDDEEEE | ||
| 19 | + * - [0-1] Q Layout: 2=TND, 3=BNSD | ||
| 20 | + * - [2-4] Mask Type: 0=NoMask, 3=CausalMask | ||
| 21 | + * - [5-7] Softmax Precision: 0=Float, 1=Half | ||
| 22 | + * - [8-10] PagedCache Flag: 0=NoCache, 1=WithCache | ||
| 23 | + * - [11-13] KV Layout: 00=TND, 20=BNSD | ||
| 24 | + * - [14-15] Data Type: 00=FP16, 22=BF16 | ||
| 25 | + * - [16-18] Operator Category: 900=EagleQuantBlockSparseAttention | ||
| 26 | + */ | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +// FP16, Q=TND, KV=TND, No PagedCache, Float Softmax, No Mask | ||
| 32 | + | ||
| 33 | + | ||
| 34 | +// FP16, Q=TND, KV=TND, No PagedCache, Half Softmax, No Mask | ||
| 35 | + | ||
| 36 | + | ||
| 37 | +// BF16, Q=TND, KV=TND, No PagedCache, Float Softmax, No Mask | ||
| 38 | + | ||
| 39 | + | ||
| 40 | +// FP16, Q=BNSD, KV=BNSD, No PagedCache, Float Softmax, No Mask | ||
| 41 | + | ||
| 42 | + | ||
| 43 | +// FP16, Q=BNSD, KV=BNSD, No PagedCache, Half Softmax, No Mask | ||
| 44 | + | ||
| 45 | + | ||
| 46 | +// BF16, Q=BNSD, KV=BNSD, No PagedCache, Float Softmax, No Mask | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + // LSE Output versions (LSE_MODE::OUT_ONLY) | ||
| 50 | +// FP16, Q=TND, KV=TND, No PagedCache, Float Softmax, No Mask, LSE Output | ||
| 51 | + | ||
| 52 | + | ||
| 53 | +// FP16, Q=TND, KV=TND, No PagedCache, Half Softmax, No Mask, LSE Output | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +// BF16, Q=TND, KV=TND, No PagedCache, Float Softmax, No Mask, LSE Output | ||
| 57 | + | ||
| 58 | + | ||
| 59 | +// FP16, Q=BNSD, KV=BNSD, No PagedCache, Float Softmax, No Mask, LSE Output | ||
| 60 | + | ||
| 61 | + | ||
| 62 | +// FP16, Q=BNSD, KV=BNSD, No PagedCache, Half Softmax, No Mask, LSE Output | ||
| 63 | + | ||
| 64 | + | ||
| 65 | +// BF16, Q=BNSD, KV=BNSD, No PagedCache, Float Softmax, No Mask, LSE Output | ||
| 66 | + | ||
| 67 | + | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + | ||
| 76 | + | ||
| 77 | + | ||
| 78 | + | ||
| 79 | + | ||
| 80 | + | ||
| 81 | + | ||
| 82 | + | ||
| 83 | + | ||
| @@ -0,0 +1,179 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +using namespace AscendC; | ||
| 31 | +using namespace matmul; | ||
| 32 | + | ||
| 33 | +namespace RfaKenelCommon { | ||
| 34 | + constexpr uint32_t QK_READY_ID = 1; | ||
| 35 | + constexpr uint32_t SOFTMAX_READY_ID = 2; | ||
| 36 | + constexpr uint32_t PV_READY_ID = 3; | ||
| 37 | + constexpr uint32_t MASKTOIDX_READY_ID = 4; | ||
| 38 | + | ||
| 39 | + constexpr uint32_t BLOCK_SIZE = 16; | ||
| 40 | + constexpr uint32_t WORKSPACE_BLOCK_SIZE_DB = 131072; | ||
| 41 | + constexpr uint32_t TMP_SIZE_DECODER = 32768; | ||
| 42 | + | ||
| 43 | + constexpr int32_t TILING_BATCH = 0; | ||
| 44 | + constexpr int32_t TILING_NUMHEADS = 1; | ||
| 45 | + constexpr int32_t TILING_HEADDIM = 2; | ||
| 46 | + constexpr int32_t TILING_NUMBLOKS = 3; | ||
| 47 | + constexpr int32_t TILING_BLOCKSIZE = 4; | ||
| 48 | + constexpr int32_t TILING_MAXBLOCKS = 5; | ||
| 49 | + constexpr int32_t TILING_TOR = 6; | ||
| 50 | + constexpr int32_t TILING_KVHEADS = 7; | ||
| 51 | + constexpr int32_t TILING_HEADSIZE = 8; | ||
| 52 | + constexpr int32_t TILING_PARASIZE = 9; | ||
| 53 | + constexpr int32_t TILING_HEAD_SPLIT_SIZE = 10; | ||
| 54 | + constexpr int32_t TILING_HEAD_SPLIT_NUM = 11; | ||
| 55 | + constexpr int32_t TILING_HEADDIM_ROPE = 13; | ||
| 56 | + constexpr int32_t TILING_MAX_KVSEQLEN = 14; | ||
| 57 | + constexpr int32_t TILING_KVSPLIT = 15; | ||
| 58 | + constexpr int32_t TILING_KVCORENUM = 16; | ||
| 59 | + constexpr int32_t TILING_TOTAL_QTOKENS = 18; | ||
| 60 | + constexpr int32_t TILING_FORMERTASKNUM = 19; | ||
| 61 | + constexpr int32_t TILING_TAILTASKNUM = 20; | ||
| 62 | + constexpr int32_t TILING_BLOCKSIZE_CALC = 25; | ||
| 63 | + constexpr int32_t TILING_HEADDIM_K_SPLIT = 38; | ||
| 64 | + constexpr int32_t TILING_HEADDIM_V_SPLIT = 39; | ||
| 65 | + constexpr int32_t TILING_HEADDIM_V_SPLIT_VECTOR_FORMER = 40; | ||
| 66 | + constexpr int32_t TILING_HEADDIM_V_SPLIT_VECTOR_TAIL = 41; | ||
| 67 | + | ||
| 68 | + constexpr int32_t NUM1 = 1; | ||
| 69 | + constexpr int32_t NUM4 = 4; | ||
| 70 | + | ||
| 71 | + constexpr int32_t NUM64 = 64; | ||
| 72 | + constexpr int32_t NUM512 = 512; | ||
| 73 | + constexpr int32_t NUM576 = 576; | ||
| 74 | + constexpr uint32_t BASIC_BLOCK_SIZE = 128; | ||
| 75 | + constexpr int32_t Q_BLK = 128; | ||
| 76 | + constexpr int32_t MAX_STACK_LEN = 512; | ||
| 77 | + constexpr int32_t PRE_LAUNCH = 2; | ||
| 78 | + | ||
| 79 | + constexpr uint32_t FLOAT_VECTOR_SIZE = 64; | ||
| 80 | + | ||
| 81 | + constexpr uint32_t UNIT_BLOCK_STACK_NUM = 4; | ||
| 82 | + | ||
| 83 | + constexpr uint32_t Q_TILE_CEIL = 128; | ||
| 84 | + constexpr uint32_t MAX_KV_STACK_LEN = 512; //可配置1024或512 | ||
| 85 | + | ||
| 86 | + template <typename T> | ||
| 87 | + __aicore__ inline T AlignUp(T a, T b) | ||
| 88 | + { | ||
| 89 | + return (b == 0) ? 0 : (a + b - 1) / b * b; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + template <typename T> | ||
| 93 | + __aicore__ inline T Min(T a, T b) | ||
| 94 | + { | ||
| 95 | + return (a > b) ? b : a; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + enum class cvPipeLineType { | ||
| 99 | + FAI_COMMON_NORMAL = 0, | ||
| 100 | + FAI_COMMON_CHUNK_MASK = 1, | ||
| 101 | + FAI_SPARSE_BLOCK = 2 | ||
| 102 | + }; | ||
| 103 | + | ||
| 104 | + enum class SparseMaskType { | ||
| 105 | + NO_MASK = 0, | ||
| 106 | + MASK_SPEC = 1, | ||
| 107 | + MASK_CAUSUAL = 2, | ||
| 108 | + SPARSE_BLOCK = 3 | ||
| 109 | + }; | ||
| 110 | + | ||
| 111 | + __aicore__ inline | ||
| 112 | + uint32_t GetQNBlockTile(uint32_t qSeqlen, uint32_t groupSize) | ||
| 113 | + { | ||
| 114 | + uint32_t qNBlockTile = 1; | ||
| 115 | + return qNBlockTile; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + __aicore__ inline | ||
| 119 | + uint32_t GetQSBlockTile(uint32_t kvSeqlen) | ||
| 120 | + { | ||
| 121 | + uint32_t qSBlockTile = Q_BLK; | ||
| 122 | + return qSBlockTile; | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + __aicore__ inline | ||
| 126 | + uint32_t GetQBlocks(int32_t qseqlen, int32_t x) | ||
| 127 | + { | ||
| 128 | + uint32_t qBlocksInX = (x + BASIC_BLOCK_SIZE - 1) / BASIC_BLOCK_SIZE; | ||
| 129 | + uint32_t completeXBlocks = x != 0 ? qseqlen / x : qseqlen / BASIC_BLOCK_SIZE; | ||
| 130 | + uint32_t remainingSeqlen = x != 0 ? qseqlen - completeXBlocks * x : qseqlen % BASIC_BLOCK_SIZE; | ||
| 131 | + uint32_t remainingBlocks = (remainingSeqlen + BASIC_BLOCK_SIZE - 1) / BASIC_BLOCK_SIZE; | ||
| 132 | + return qBlocksInX * completeXBlocks + remainingBlocks; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + | ||
| 136 | + // EagleQuantBlockSparseAttention Kernel Parameters | ||
| 137 | + struct EagleQuantBlockSparseAttentionKernelParams { | ||
| 138 | + // 输入张量 | ||
| 139 | + GM_ADDR q; // Query张量 | ||
| 140 | + GM_ADDR k; // Key张量 | ||
| 141 | + GM_ADDR v; // Value张量 | ||
| 142 | + GM_ADDR blockSparseMask; // 适配新增的张量 | ||
| 143 | + GM_ADDR mask; // 掩码张量 | ||
| 144 | + GM_ADDR blockTables; // 块表 | ||
| 145 | + GM_ADDR actualQseqlen; // 实际Q序列长度 | ||
| 146 | + GM_ADDR actualKvseqlen; // 实际KV序列长度 | ||
| 147 | + | ||
| 148 | + | ||
| 149 | + // 输出和工作空间 | ||
| 150 | + GM_ADDR o; // 输出张量 | ||
| 151 | + GM_ADDR lse; | ||
| 152 | + GM_ADDR workspace; | ||
| 153 | + GM_ADDR tiling; // Tiling数据 | ||
| 154 | + | ||
| 155 | + // 默认构造函数 | ||
| 156 | + __aicore__ inline | ||
| 157 | + EagleQuantBlockSparseAttentionKernelParams() {} | ||
| 158 | + | ||
| 159 | + // 带参数的构造函数(新增了参数的构造器) | ||
| 160 | + __aicore__ inline | ||
| 161 | + EagleQuantBlockSparseAttentionKernelParams( | ||
| 162 | + GM_ADDR q_, GM_ADDR k_, GM_ADDR v_, GM_ADDR blockSparseMask_, GM_ADDR mask_, GM_ADDR blockTables_, | ||
| 163 | + GM_ADDR actualQseqlen_, GM_ADDR actualKvseqlen_, | ||
| 164 | + GM_ADDR o_, GM_ADDR lse_, GM_ADDR workspace_, | ||
| 165 | + GM_ADDR tiling_) | ||
| 166 | + : q(q_), k(k_), v(v_), blockSparseMask(blockSparseMask_), mask(mask_), blockTables(blockTables_), | ||
| 167 | + actualQseqlen(actualQseqlen_), actualKvseqlen(actualKvseqlen_), | ||
| 168 | + o(o_), | ||
| 169 | + lse(lse_), | ||
| 170 | + workspace(workspace_), | ||
| 171 | + tiling(tiling_) | ||
| 172 | + {} | ||
| 173 | + }; | ||
| 174 | + | ||
| 175 | + // 为了兼容性,保留旧名称的别名(逐步废弃) | ||
| 176 | + using FASparseKernelParams = EagleQuantBlockSparseAttentionKernelParams; | ||
| 177 | +} | ||
| 178 | + | ||
| 179 | + | ||
| @@ -0,0 +1,273 @@ | |||
| 1 | +/** | ||
| 2 | + * This program is free software, you can redistribute it and/or modify. | ||
| 3 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 4 | + * This file is a part of the CANN Open Software. | ||
| 5 | + * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace tla { | ||
| 20 | + | ||
| 21 | +namespace detail { | ||
| 22 | + | ||
| 23 | +template <class T, class F, int... I> | ||
| 24 | +HOST_DEVICE constexpr | ||
| 25 | +auto apply(T&& t, F&& f, seq<I...>) | ||
| 26 | +{ | ||
| 27 | + return f(get<I>(static_cast<T&&>(t))...); | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +template <class T, class F, class G, int... I> | ||
| 31 | +HOST_DEVICE constexpr | ||
| 32 | +auto tapply(T&& t, F&& f, G&& g, seq<I...>) | ||
| 33 | +{ | ||
| 34 | + return g(f(get<I>(static_cast<T&&>(t)))...); | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +template <class T0, class T1, class F, class G, int... I> | ||
| 38 | +HOST_DEVICE constexpr | ||
| 39 | +auto tapply(T0&& t0, T1&& t1, F&& f, G&& g, seq<I...>) | ||
| 40 | +{ | ||
| 41 | + return g(f(get<I>(static_cast<T0&&>(t0)), | ||
| 42 | + get<I>(static_cast<T1&&>(t1)))...); | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +} // end namespace detail | ||
| 46 | + | ||
| 47 | +template <class T, class F> | ||
| 48 | +HOST_DEVICE constexpr | ||
| 49 | +auto apply(T&& t, F&& f) | ||
| 50 | +{ | ||
| 51 | + return detail::apply(static_cast<T&&>(t), f, tuple_seq<T>{}); | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +template <class T, class F, class G> | ||
| 55 | +HOST_DEVICE constexpr | ||
| 56 | +auto transform_apply(T&& t, F&& f, G&& g) | ||
| 57 | +{ | ||
| 58 | + if constexpr (is_tuple<remove_cvref_t<T>>::value) { | ||
| 59 | + return detail::tapply(static_cast<T&&>(t), f, g, tuple_seq<T>{}); | ||
| 60 | + } else { | ||
| 61 | + return g(f(static_cast<T&&>(t))); | ||
| 62 | + } | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +template <class T0, class T1, class F, class G> | ||
| 66 | +HOST_DEVICE constexpr | ||
| 67 | +auto transform_apply(T0&& t0, T1&& t1, F&& f, G&& g) | ||
| 68 | +{ | ||
| 69 | + if constexpr (is_tuple<remove_cvref_t<T0>>::value) { | ||
| 70 | + return detail::tapply(static_cast<T0&&>(t0), static_cast<T1&&>(t1), f, g, tuple_seq<T0>{}); | ||
| 71 | + } else { | ||
| 72 | + return g(f(static_cast<T0&&>(t0), static_cast<T1&&>(t1))); | ||
| 73 | + } | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +template <class T, class F> | ||
| 77 | +HOST_DEVICE constexpr | ||
| 78 | +void for_each(T&& t, F&& f) | ||
| 79 | +{ | ||
| 80 | + if constexpr (is_tuple<remove_cvref_t<T>>::value) { | ||
| 81 | + return detail::apply(t, [&](auto&&... a) { (f(static_cast<decltype(a)&&>(a)), ...); }, tuple_seq<T>{}); | ||
| 82 | + } else { | ||
| 83 | + return f(static_cast<T&&>(t)); | ||
| 84 | + } | ||
| 85 | +} | ||
| 86 | + | ||
| 87 | +struct UnpackedMakeTuple { | ||
| 88 | + template <class... T> | ||
| 89 | + HOST_DEVICE constexpr | ||
| 90 | + auto operator()(T const&... a) const { | ||
| 91 | + return tla::MakeTuple(a...); | ||
| 92 | + } | ||
| 93 | +}; | ||
| 94 | + | ||
| 95 | +template <class T0, class T1, class F> | ||
| 96 | +HOST_DEVICE constexpr | ||
| 97 | +auto transform(T0 const& t0, T1 const& t1, F&& f) | ||
| 98 | +{ | ||
| 99 | + if constexpr (is_tuple<T0>::value) { | ||
| 100 | + static_assert(tuple_size<T0>::value == tuple_size<T1>::value, "Mismatched tuple_size"); | ||
| 101 | + return detail::tapply(t0, t1, f, UnpackedMakeTuple{}, tuple_seq<T0>{}); | ||
| 102 | + } else { | ||
| 103 | + return f(t0, t1); | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +template <size_t I, class T, | ||
| 108 | + TLA_REQUIRES(tla::is_integral<tla::remove_cvref_t<T>>::value)> | ||
| 109 | +HOST_DEVICE constexpr | ||
| 110 | +decltype(auto) get(T&& t) noexcept | ||
| 111 | +{ | ||
| 112 | + static_assert(I == 0, "Index out of range"); | ||
| 113 | + return static_cast<T&&>(t); | ||
| 114 | +} | ||
| 115 | + | ||
| 116 | +template <size_t I0, size_t I1, size_t... Is, class T> | ||
| 117 | +HOST_DEVICE constexpr | ||
| 118 | +decltype(auto) get(T&& t) noexcept | ||
| 119 | +{ | ||
| 120 | + return get<I1, Is...>(get<I0>(static_cast<T&&>(t))); | ||
| 121 | +} | ||
| 122 | + | ||
| 123 | +// max | ||
| 124 | +template <class T0, class... Ts> | ||
| 125 | +HOST_DEVICE constexpr | ||
| 126 | +auto max(T0 const& t0, Ts const&... ts); | ||
| 127 | + | ||
| 128 | +struct UnpackedMax { | ||
| 129 | + template <class... T> | ||
| 130 | + HOST_DEVICE constexpr | ||
| 131 | + auto operator()(T const&... v) const { | ||
| 132 | + return tla::max(v...); | ||
| 133 | + } | ||
| 134 | +}; | ||
| 135 | + | ||
| 136 | +template <class T0, class... Ts> | ||
| 137 | +HOST_DEVICE constexpr | ||
| 138 | +auto max(T0 const& t0, Ts const&... ts) | ||
| 139 | +{ | ||
| 140 | + if constexpr (is_tuple<T0>::value) { | ||
| 141 | + return tla::max(tla::apply(t0, UnpackedMax{}), ts...); | ||
| 142 | + } else if constexpr (sizeof...(Ts) == 0) { | ||
| 143 | + return t0; | ||
| 144 | + } else { | ||
| 145 | + return tla::max(t0, tla::max(ts...)); | ||
| 146 | + } | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +// rank | ||
| 150 | +template <int... Is, class Tuple> | ||
| 151 | +HOST_DEVICE constexpr | ||
| 152 | +auto rank(Tuple const& t) | ||
| 153 | +{ | ||
| 154 | + if constexpr (sizeof...(Is) == 0) { | ||
| 155 | + if constexpr (is_tuple<Tuple>::value) { | ||
| 156 | + return Int<tuple_size<Tuple>::value>{}; | ||
| 157 | + } else { | ||
| 158 | + return Int<1>{}; | ||
| 159 | + } | ||
| 160 | + } else { | ||
| 161 | + return rank(get<Is...>(t)); | ||
| 162 | + } | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +template <class Tuple> | ||
| 166 | +using rank_t = decltype(rank(std::declval<Tuple>())); | ||
| 167 | + | ||
| 168 | +template <class Tuple> | ||
| 169 | +constexpr auto rank_v = rank_t<Tuple>::value; | ||
| 170 | + | ||
| 171 | +// depth | ||
| 172 | +template <int... Is, class Tuple> | ||
| 173 | +HOST_DEVICE constexpr | ||
| 174 | +auto depth(Tuple const& t); | ||
| 175 | + | ||
| 176 | +struct UnpackedDepth { | ||
| 177 | + template <class... T> | ||
| 178 | + HOST_DEVICE constexpr | ||
| 179 | + auto operator()(T const&... v) const { | ||
| 180 | + return tla::max(depth(v)...); | ||
| 181 | + } | ||
| 182 | +}; | ||
| 183 | + | ||
| 184 | +template <int... Is, class Tuple> | ||
| 185 | +HOST_DEVICE constexpr | ||
| 186 | +auto depth(Tuple const& t) | ||
| 187 | +{ | ||
| 188 | + if constexpr (sizeof...(Is) == 0) { | ||
| 189 | + if constexpr (is_tuple<Tuple>::value) { | ||
| 190 | + return Int<1>{} + tla::apply(t, UnpackedDepth{}); | ||
| 191 | + } else { | ||
| 192 | + return Int<0>{}; | ||
| 193 | + } | ||
| 194 | + } else { | ||
| 195 | + return depth(get<Is...>(t)); | ||
| 196 | + } | ||
| 197 | +} | ||
| 198 | + | ||
| 199 | +template <class Tuple> | ||
| 200 | +using depth_t = decltype(depth(std::declval<Tuple>())); | ||
| 201 | + | ||
| 202 | +template <class Tuple> | ||
| 203 | +constexpr auto depth_v = depth_t<Tuple>::value; | ||
| 204 | + | ||
| 205 | +struct MultipliesUnaryLfold { | ||
| 206 | + template <class... T> | ||
| 207 | + HOST_DEVICE constexpr | ||
| 208 | + auto operator()(T const&... v) const { | ||
| 209 | + return (... * v); | ||
| 210 | + } | ||
| 211 | +}; | ||
| 212 | + | ||
| 213 | +// Implementation of product as a function object | ||
| 214 | +struct Product { | ||
| 215 | + template <class IntTuple> | ||
| 216 | + HOST_DEVICE constexpr | ||
| 217 | + auto operator()(IntTuple const& a) const | ||
| 218 | + { | ||
| 219 | + if constexpr (is_tuple<IntTuple>::value) { | ||
| 220 | + if constexpr (tuple_size<IntTuple>::value == 0) { | ||
| 221 | + return Int<1>{}; | ||
| 222 | + } else { | ||
| 223 | + return tla::transform_apply(a, Product{}, MultipliesUnaryLfold{}); | ||
| 224 | + } | ||
| 225 | + } else if constexpr (tla::is_integral<IntTuple>::value) { | ||
| 226 | + return a; | ||
| 227 | + } | ||
| 228 | + } | ||
| 229 | +}; | ||
| 230 | + | ||
| 231 | +namespace detail { | ||
| 232 | + | ||
| 233 | +template <size_t N, typename Sequence> | ||
| 234 | +struct MakeZeroTupleImpl; | ||
| 235 | + | ||
| 236 | +template <size_t N, size_t... Is> | ||
| 237 | +struct MakeZeroTupleImpl<N, tla::index_sequence<Is...>> { | ||
| 238 | + using type = tla::tuple<tla::Int<Is*0>...>; | ||
| 239 | +}; | ||
| 240 | + | ||
| 241 | +template <size_t N> | ||
| 242 | +using MakeZeroTuple = typename MakeZeroTupleImpl<N, tla::make_index_sequence<N>>::type; | ||
| 243 | + | ||
| 244 | +} // end namespace detail | ||
| 245 | + | ||
| 246 | +// Add | ||
| 247 | +template <class IntTupleA, class IntTupleB> | ||
| 248 | +HOST_DEVICE constexpr | ||
| 249 | +auto Add(IntTupleA const& a, IntTupleB const& b); | ||
| 250 | + | ||
| 251 | +struct UnpackedAdd { | ||
| 252 | + template <class IntTupleA, class IntTupleB> | ||
| 253 | + HOST_DEVICE constexpr | ||
| 254 | + auto operator()(IntTupleA const& x, IntTupleB const& y) const { | ||
| 255 | + return Add(x, y); | ||
| 256 | + } | ||
| 257 | +}; | ||
| 258 | + | ||
| 259 | +template <class IntTupleA, class IntTupleB> | ||
| 260 | +HOST_DEVICE constexpr | ||
| 261 | +auto Add(IntTupleA const& a, IntTupleB const& b) | ||
| 262 | +{ | ||
| 263 | + if constexpr (is_tuple<IntTupleA>::value && is_tuple<IntTupleB>::value) { | ||
| 264 | + static_assert(tuple_size<IntTupleA>::value == tuple_size<IntTupleB>::value, "Mismatched ranks"); | ||
| 265 | + return transform(a, b, UnpackedAdd{}); | ||
| 266 | + } else { | ||
| 267 | + return tla::add(a, b); | ||
| 268 | + } | ||
| 269 | +} | ||
| 270 | + | ||
| 271 | +} // end namespace tla | ||
| 272 | + | ||
| 273 | + | ||
| @@ -0,0 +1,612 @@ | |||
| 1 | +/** | ||
| 2 | + * This program is free software, you can redistribute it and/or modify. | ||
| 3 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 4 | + * This file is a part of the CANN Open Software. | ||
| 5 | + * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace tla { | ||
| 21 | + | ||
| 22 | +// Aliases | ||
| 23 | + | ||
| 24 | +template <class... Shapes> | ||
| 25 | +using Shape = tla::tuple<Shapes...>; | ||
| 26 | + | ||
| 27 | +template <class... Strides> | ||
| 28 | +using Stride = tla::tuple<Strides...>; | ||
| 29 | + | ||
| 30 | +template <class... Coords> | ||
| 31 | +using Coord = tla::tuple<Coords...>; | ||
| 32 | + | ||
| 33 | +template <class... Ts> | ||
| 34 | +HOST_DEVICE constexpr | ||
| 35 | +Shape<Ts...> MakeShape(Ts const&... t) { | ||
| 36 | + return {t...}; | ||
| 37 | +} | ||
| 38 | +template <class... Ts> | ||
| 39 | +HOST_DEVICE constexpr | ||
| 40 | +Stride<Ts...> MakeStride(Ts const&... t) { | ||
| 41 | + return {t...}; | ||
| 42 | +} | ||
| 43 | +template <class... Ts> | ||
| 44 | +HOST_DEVICE constexpr | ||
| 45 | +Coord<Ts...> MakeCoord(Ts const&... t) { | ||
| 46 | + return {t...}; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +// | ||
| 50 | +// Layout | ||
| 51 | +// | ||
| 52 | + | ||
| 53 | +template <class Shape, class Stride> | ||
| 54 | +struct Layout : private tla::tuple<Shape, Stride> { | ||
| 55 | + // NOTE: This defaults static Shapes/Strides correctly, but not dynamic | ||
| 56 | + HOST_DEVICE constexpr | ||
| 57 | + Layout(Shape const& shape = {}, Stride const& stride = {}) | ||
| 58 | + : tla::tuple<Shape, Stride>(shape, stride) {} | ||
| 59 | + | ||
| 60 | + // | ||
| 61 | + // Accessors | ||
| 62 | + // | ||
| 63 | + | ||
| 64 | + static constexpr int rank = rank_v<Stride>; | ||
| 65 | + static constexpr int depth = depth_v<Stride>; | ||
| 66 | + | ||
| 67 | + template <int... I> | ||
| 68 | + HOST_DEVICE constexpr | ||
| 69 | + decltype(auto) shape() | ||
| 70 | + { | ||
| 71 | + return get<0, I...>(static_cast<tla::tuple<Shape, Stride>&>(*this)); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + template <int... I> | ||
| 75 | + HOST_DEVICE constexpr | ||
| 76 | + decltype(auto) shape() const | ||
| 77 | + { | ||
| 78 | + return get<0, I...>(static_cast<tla::tuple<Shape, Stride> const&>(*this)); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + template <int... I> | ||
| 82 | + HOST_DEVICE constexpr | ||
| 83 | + decltype(auto) stride() | ||
| 84 | + { | ||
| 85 | + return get<1, I...>(static_cast<tla::tuple<Shape, Stride>&>(*this)); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + template <int... I> | ||
| 89 | + HOST_DEVICE constexpr | ||
| 90 | + decltype(auto) stride() const | ||
| 91 | + { | ||
| 92 | + return get<1, I...>(static_cast<tla::tuple<Shape, Stride> const&>(*this)); | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + template <class Coord> | ||
| 96 | + HOST_DEVICE constexpr | ||
| 97 | + auto operator()(Coord const& coord) const | ||
| 98 | + { | ||
| 99 | + return crd2offset(coord, shape(), stride()); | ||
| 100 | + } | ||
| 101 | +}; | ||
| 102 | + | ||
| 103 | +// Layout construction | ||
| 104 | + | ||
| 105 | +template <class Shape, class Stride> | ||
| 106 | +HOST_DEVICE constexpr | ||
| 107 | +auto MakeLayout(Shape const& shape, Stride const& stride) | ||
| 108 | +{ | ||
| 109 | + static_assert(is_tuple<Shape>::value || is_integral<Shape>::value); | ||
| 110 | + static_assert(is_tuple<Stride>::value || is_integral<Stride>::value); | ||
| 111 | + return Layout<Shape, Stride>(shape, stride); | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +// Convenience tags for common layouts | ||
| 115 | + | ||
| 116 | +template <class LayoutTag> | ||
| 117 | +HOST_DEVICE constexpr | ||
| 118 | +auto MakeLayoutFromTag(LayoutTag const& tag) | ||
| 119 | +{ | ||
| 120 | + static_assert(std::is_same_v<LayoutTag, NpuArch::layout::RowMajor> || | ||
| 121 | + std::is_same_v<LayoutTag, NpuArch::layout::ColumnMajor> || | ||
| 122 | + std::is_same_v<LayoutTag, NpuArch::layout::zN> || | ||
| 123 | + std::is_same_v<LayoutTag, NpuArch::layout::nZ>, | ||
| 124 | + "Unsupported LayoutTag for MakeLayoutFromTag, only support NpuArch::layout::RowMajor or" | ||
| 125 | + "NpuArch::layout::ColumnMajor or NpuArch::layout::zN or NpuArch::layout::nZ"); | ||
| 126 | + | ||
| 127 | + if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::RowMajor>) { | ||
| 128 | + return MakeLayout(MakeShape(tag.shape(0), tag.shape(1)), MakeStride(tag.stride(0), Int<1>{})); | ||
| 129 | + } else if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::ColumnMajor>) { | ||
| 130 | + return MakeLayout(MakeShape(tag.shape(0), tag.shape(1)), MakeStride(Int<1>{}, tag.stride(1))); | ||
| 131 | + } else { // zN or nZ | ||
| 132 | + return MakeLayout(MakeShape(MakeShape(tag.shape(0), tag.shape(1)), MakeShape(tag.shape(2), tag.shape(3))), | ||
| 133 | + MakeStride(MakeStride(tag.stride(0), tag.stride(1)), MakeStride(tag.stride(2), tag.stride(3)))); | ||
| 134 | + } | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +// Return the shape of a mode | ||
| 138 | +template <int... Is, class Shape, class Stride> | ||
| 139 | +HOST_DEVICE constexpr | ||
| 140 | +decltype(auto) shape(Layout<Shape, Stride>& layout) | ||
| 141 | +{ | ||
| 142 | + return layout.template shape<Is...>(); | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +template <int... Is, class Shape, class Stride> | ||
| 146 | +HOST_DEVICE constexpr | ||
| 147 | +decltype(auto) shape(Layout<Shape, Stride> const& layout) | ||
| 148 | +{ | ||
| 149 | + return layout.template shape<Is...>(); | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +// Return the stride of a mode | ||
| 153 | +template <int... Is, class Shape, class Stride> | ||
| 154 | +HOST_DEVICE constexpr | ||
| 155 | +decltype(auto) stride(Layout<Shape, Stride>& layout) | ||
| 156 | +{ | ||
| 157 | + return layout.template stride<Is...>(); | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | +template <int... Is, class Shape, class Stride> | ||
| 161 | +HOST_DEVICE constexpr | ||
| 162 | +decltype(auto) stride(Layout<Shape, Stride> const& layout) | ||
| 163 | +{ | ||
| 164 | + return layout.template stride<Is...>(); | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +// Return the rank of layout | ||
| 168 | +template <int... Is, class Shape, class Stride> | ||
| 169 | +HOST_DEVICE constexpr | ||
| 170 | +auto rank(Layout<Shape, Stride> const& layout) | ||
| 171 | +{ | ||
| 172 | + return rank(shape<Is...>(layout)); | ||
| 173 | +} | ||
| 174 | + | ||
| 175 | +// Return the depth of the layout | ||
| 176 | +template <int... Is, class Shape, class Stride> | ||
| 177 | +HOST_DEVICE constexpr | ||
| 178 | +auto depth(Layout<Shape, Stride> const& layout) | ||
| 179 | +{ | ||
| 180 | + return depth(shape<Is...>(layout)); | ||
| 181 | +} | ||
| 182 | + | ||
| 183 | +// Return the offset of coord | ||
| 184 | +template <class Coord, class Shape, class Stride> | ||
| 185 | +HOST_DEVICE constexpr | ||
| 186 | +auto crd2offset(Coord const& coord, Shape const& shape, Stride const& stride); | ||
| 187 | + | ||
| 188 | +namespace detail { | ||
| 189 | + | ||
| 190 | +template <class Coord, class Shape, class Stride, int... Is> | ||
| 191 | +HOST_DEVICE constexpr | ||
| 192 | +auto crd2offset_ttt(Coord const& coord, Shape const& shape, Stride const& stride, seq<Is...>) | ||
| 193 | +{ | ||
| 194 | + return (... + crd2offset(get<Is>(coord), get<Is>(shape), get<Is>(stride))); | ||
| 195 | +} | ||
| 196 | + | ||
| 197 | +template <class CInt, class STuple, class DTuple, int I0, int... Is> | ||
| 198 | +HOST_DEVICE constexpr | ||
| 199 | +auto crd2offset_itt(CInt const& coord, STuple const& shape, DTuple const& stride, seq<I0, Is...>) | ||
| 200 | +{ | ||
| 201 | + if constexpr (sizeof...(Is) == 0) { // Avoid recursion and mod on single/last iter | ||
| 202 | + return crd2offset(coord, get<I0>(shape), get<I0>(stride)); | ||
| 203 | + } else if constexpr (is_constant<0, CInt>::value) { | ||
| 204 | + return crd2offset(_0{}, get<I0>(shape), get<I0>(stride)) + | ||
| 205 | + (_0{} + ... + crd2offset(_0{}, get<Is>(shape), get<Is>(stride))); | ||
| 206 | + } else { // General case | ||
| 207 | + return crd2offset(coord % Product{}(get<I0>(shape)), get<I0>(shape), get<I0>(stride)) + | ||
| 208 | + crd2offset_itt(coord / Product{}(get<I0>(shape)), shape, stride, seq<Is...>{}); | ||
| 209 | + } | ||
| 210 | +} | ||
| 211 | + | ||
| 212 | +} // end namespace detail | ||
| 213 | + | ||
| 214 | +template <class Coord, class Shape, class Stride> | ||
| 215 | +HOST_DEVICE constexpr | ||
| 216 | +auto crd2offset(Coord const& coord, Shape const& shape, Stride const& stride) | ||
| 217 | +{ | ||
| 218 | + if constexpr (is_tuple<Coord>::value) { | ||
| 219 | + if constexpr (is_tuple<Shape>::value) { // tuple tuple tuple | ||
| 220 | + static_assert(tuple_size<Coord>::value == tuple_size<Shape>::value, "Mismatched Ranks"); | ||
| 221 | + static_assert(tuple_size<Coord>::value == tuple_size<Stride>::value, "Mismatched Ranks"); | ||
| 222 | + return detail::crd2offset_ttt(coord, shape, stride, tuple_seq<Coord>{}); | ||
| 223 | + } else { // tuple "int" "int" | ||
| 224 | + static_assert(sizeof(Coord) == 0, "Invalid parameters"); | ||
| 225 | + } | ||
| 226 | + } else { | ||
| 227 | + if constexpr (is_tuple<Shape>::value) { // "int" tuple tuple | ||
| 228 | + static_assert(tuple_size<Shape>::value == tuple_size<Stride>::value, "Mismatched Ranks"); | ||
| 229 | + return detail::crd2offset_itt(coord, shape, stride, tuple_seq<Shape>{}); | ||
| 230 | + } else { // "int" "int" "int" | ||
| 231 | + return coord * stride; | ||
| 232 | + } | ||
| 233 | + } | ||
| 234 | +} | ||
| 235 | + | ||
| 236 | +template <class Layout> | ||
| 237 | +struct is_layout : false_type {}; | ||
| 238 | +template <class Shape, class Stride> | ||
| 239 | +struct is_layout<Layout<Shape, Stride>> : true_type {}; | ||
| 240 | + | ||
| 241 | +// Layout Check | ||
| 242 | +namespace detail { | ||
| 243 | + | ||
| 244 | +template <class Layout, class Enable = void> | ||
| 245 | +struct isVector { | ||
| 246 | + static bool const value = false; | ||
| 247 | +}; | ||
| 248 | + | ||
| 249 | +template <class Layout> | ||
| 250 | +struct isVector<Layout, std::enable_if_t<Layout::depth == 1 && Layout::rank == 1>> { | ||
| 251 | + static bool const value = (stride<0>(Layout{}) == 1); | ||
| 252 | +}; | ||
| 253 | + | ||
| 254 | +template <class Layout, class Enable = void> | ||
| 255 | +struct isRowMajor { | ||
| 256 | + static bool const value = false; | ||
| 257 | +}; | ||
| 258 | + | ||
| 259 | +template <class Layout> | ||
| 260 | +struct isRowMajor<Layout, std::enable_if_t<Layout::depth == 1 && Layout::rank == 2>> { | ||
| 261 | + static bool const value = (stride<1>(Layout{}) == 1); | ||
| 262 | +}; | ||
| 263 | + | ||
| 264 | +template <class Layout, class Enable = void> | ||
| 265 | +struct isColumnMajor { | ||
| 266 | + static bool const value = false; | ||
| 267 | +}; | ||
| 268 | + | ||
| 269 | +template <class Layout> | ||
| 270 | +struct isColumnMajor<Layout, std::enable_if_t<Layout::depth == 1 && Layout::rank == 2>> { | ||
| 271 | + static bool const value = (stride<0>(Layout{}) == 1); | ||
| 272 | +}; | ||
| 273 | + | ||
| 274 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 275 | +struct iszN { | ||
| 276 | + static bool const value = false; | ||
| 277 | +}; | ||
| 278 | + | ||
| 279 | +template <class Element, class Layout> | ||
| 280 | +struct iszN<Element, Layout, | ||
| 281 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 2 && | ||
| 282 | + rank_v<decltype(shape<1>(Layout{}))> == 2>> { | ||
| 283 | + static constexpr uint32_t ELE_NUM_PER_C0 = NpuArch::BYTE_PER_C0 / sizeof(Element); | ||
| 284 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = NpuArch::BYTE_PER_FRACTAL / sizeof(Element); | ||
| 285 | + static bool const value = (shape<0, 0>(Layout{}) == NpuArch::C0_NUM_PER_FRACTAL && | ||
| 286 | + shape<1, 0>(Layout{}) == ELE_NUM_PER_C0 && | ||
| 287 | + stride<1, 0>(Layout{}) == 1 && | ||
| 288 | + stride<0, 1>(Layout{}) == ELE_NUM_PER_FRACTAL); | ||
| 289 | +}; | ||
| 290 | + | ||
| 291 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 292 | +struct iszZ { | ||
| 293 | + static bool const value = false; | ||
| 294 | +}; | ||
| 295 | + | ||
| 296 | +template <class Element, class Layout> | ||
| 297 | +struct iszZ<Element, Layout, | ||
| 298 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 2 && | ||
| 299 | + rank_v<decltype(shape<1>(Layout{}))> == 2>> { | ||
| 300 | + static constexpr uint32_t ELE_NUM_PER_C0 = NpuArch::BYTE_PER_C0 / sizeof(Element); | ||
| 301 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = NpuArch::BYTE_PER_FRACTAL / sizeof(Element); | ||
| 302 | + static bool const value = (shape<0, 0>(Layout{}) == NpuArch::C0_NUM_PER_FRACTAL && | ||
| 303 | + shape<1, 0>(Layout{}) == ELE_NUM_PER_C0 && | ||
| 304 | + stride<1, 0>(Layout{}) == 1 && | ||
| 305 | + stride<1, 1>(Layout{}) == ELE_NUM_PER_FRACTAL); | ||
| 306 | +}; | ||
| 307 | + | ||
| 308 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 309 | +struct isnZ { | ||
| 310 | + static bool const value = false; | ||
| 311 | +}; | ||
| 312 | + | ||
| 313 | +template <class Element, class Layout> | ||
| 314 | +struct isnZ<Element, Layout, | ||
| 315 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 2 && | ||
| 316 | + rank_v<decltype(shape<1>(Layout{}))> == 2>> { | ||
| 317 | + static constexpr uint32_t ELE_NUM_PER_C0 = NpuArch::BYTE_PER_C0 / sizeof(Element); | ||
| 318 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = NpuArch::BYTE_PER_FRACTAL / sizeof(Element); | ||
| 319 | + static bool const value = (shape<0, 0>(Layout{}) == ELE_NUM_PER_C0 && | ||
| 320 | + shape<1, 0>(Layout{}) == NpuArch::C0_NUM_PER_FRACTAL && | ||
| 321 | + stride<0, 0>(Layout{}) == 1 && | ||
| 322 | + stride<1, 1>(Layout{}) == ELE_NUM_PER_FRACTAL); | ||
| 323 | +}; | ||
| 324 | + | ||
| 325 | + | ||
| 326 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 327 | +struct isMxScaleANoTrans { | ||
| 328 | + static bool const value = false; | ||
| 329 | +}; | ||
| 330 | + | ||
| 331 | +template <class Layout> | ||
| 332 | +struct isMxScaleANoTrans<AscendC::fp8_e8m0_t, Layout, | ||
| 333 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 1 && | ||
| 334 | + rank_v<decltype(shape<1>(Layout{}))> == 2>> { | ||
| 335 | + static constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 336 | + static bool const value = | ||
| 337 | + (shape<1, 0>(Layout{}) == ELE_NUM_PER_C0 && stride<1, 0>(Layout{}) == 1 && | ||
| 338 | + stride<1, 1>(Layout{}) == ELE_NUM_PER_C0); | ||
| 339 | +}; | ||
| 340 | + | ||
| 341 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 342 | +struct isMxScaleATrans { | ||
| 343 | + static bool const value = false; | ||
| 344 | +}; | ||
| 345 | + | ||
| 346 | +template <class Layout> | ||
| 347 | +struct isMxScaleATrans<AscendC::fp8_e8m0_t, Layout, | ||
| 348 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 1 && | ||
| 349 | + rank_v<decltype(shape<1>(Layout{}))> == 2>> { | ||
| 350 | + static constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 351 | + static bool const value = | ||
| 352 | + (shape<1, 0>(Layout{}) == ELE_NUM_PER_C0 && stride<1, 0>(Layout{}) == 1 && | ||
| 353 | + stride<0>(Layout{}) == ELE_NUM_PER_C0); | ||
| 354 | +}; | ||
| 355 | + | ||
| 356 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 357 | +struct isMxScaleBNoTrans { | ||
| 358 | + static bool const value = false; | ||
| 359 | +}; | ||
| 360 | + | ||
| 361 | +template <class Layout> | ||
| 362 | +struct isMxScaleBNoTrans<AscendC::fp8_e8m0_t, Layout, | ||
| 363 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 2 && | ||
| 364 | + rank_v<decltype(shape<1>(Layout{}))> == 1>> { | ||
| 365 | + static constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 366 | + static bool const value = | ||
| 367 | + (shape<0, 0>(Layout{}) == ELE_NUM_PER_C0 && stride<0, 0>(Layout{}) == 1 && | ||
| 368 | + stride<1>(Layout{}) == ELE_NUM_PER_C0); | ||
| 369 | +}; | ||
| 370 | + | ||
| 371 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 372 | +struct isMxScaleBTrans { | ||
| 373 | + static bool const value = false; | ||
| 374 | +}; | ||
| 375 | + | ||
| 376 | +template <class Layout> | ||
| 377 | +struct isMxScaleBTrans<AscendC::fp8_e8m0_t, Layout, | ||
| 378 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 2 && | ||
| 379 | + rank_v<decltype(shape<1>(Layout{}))> == 1>> { | ||
| 380 | + static constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 381 | + static bool const value = | ||
| 382 | + (shape<0, 0>(Layout{}) == ELE_NUM_PER_C0 && stride<0, 0>(Layout{}) == 1 && | ||
| 383 | + stride<0, 1>(Layout{}) == ELE_NUM_PER_C0); | ||
| 384 | +}; | ||
| 385 | + | ||
| 386 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 387 | +struct isMxScalezZ { | ||
| 388 | + static bool const value = false; | ||
| 389 | +}; | ||
| 390 | + | ||
| 391 | +template <class Layout> | ||
| 392 | +struct isMxScalezZ<AscendC::fp8_e8m0_t, Layout, | ||
| 393 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 2 && | ||
| 394 | + rank_v<decltype(shape<1>(Layout{}))> == 2>> { | ||
| 395 | + static constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 396 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = 32; | ||
| 397 | + static bool const value = (shape<0, 0>(Layout{}) == NpuArch::C0_NUM_PER_FRACTAL && | ||
| 398 | + shape<1, 0>(Layout{}) == ELE_NUM_PER_C0 && | ||
| 399 | + stride<1, 0>(Layout{}) == 1 && | ||
| 400 | + stride<1, 1>(Layout{}) == ELE_NUM_PER_FRACTAL); | ||
| 401 | +}; | ||
| 402 | + | ||
| 403 | +template <class Element, class Layout, class Enable1 = void, class Enable2 = void> | ||
| 404 | +struct isMxScalenN { | ||
| 405 | + static bool const value = false; | ||
| 406 | +}; | ||
| 407 | + | ||
| 408 | +template <class Layout> | ||
| 409 | +struct isMxScalenN<AscendC::fp8_e8m0_t, Layout, | ||
| 410 | + std::enable_if_t<Layout::depth == 2 && Layout::rank == 2>, std::enable_if_t<rank_v<decltype(shape<0>(Layout{}))> == 2 && | ||
| 411 | + rank_v<decltype(shape<1>(Layout{}))> == 2>> { | ||
| 412 | + static constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 413 | + static constexpr uint32_t ELE_NUM_PER_FRACTAL = 32; | ||
| 414 | + static bool const value = (shape<0, 0>(Layout{}) == ELE_NUM_PER_C0 && | ||
| 415 | + shape<1, 0>(Layout{}) == NpuArch::C0_NUM_PER_FRACTAL && | ||
| 416 | + stride<0, 0>(Layout{}) == 1 && | ||
| 417 | + stride<0, 1>(Layout{}) == ELE_NUM_PER_FRACTAL); | ||
| 418 | +}; | ||
| 419 | + | ||
| 420 | + | ||
| 421 | +} // end namespace detail | ||
| 422 | + | ||
| 423 | +// Advanced Layout constructions | ||
| 424 | +// Make a vector layout. | ||
| 425 | +template <class T> | ||
| 426 | +HOST_DEVICE constexpr | ||
| 427 | +auto MakeLayout(T const& len) | ||
| 428 | +{ | ||
| 429 | + return MakeLayout(MakeShape(len), MakeStride(Int<1>{})); | ||
| 430 | +} | ||
| 431 | + | ||
| 432 | +// Make a inner layout with Rows and Cols. | ||
| 433 | +template <class Element, class LayoutTag, class T, class U> | ||
| 434 | +HOST_DEVICE constexpr | ||
| 435 | +auto MakeLayout(T const& rows, U const& cols) | ||
| 436 | +{ | ||
| 437 | + static_assert(std::is_same_v<LayoutTag, NpuArch::layout::RowMajor> || | ||
| 438 | + std::is_same_v<LayoutTag, NpuArch::layout::ColumnMajor> || | ||
| 439 | + std::is_same_v<LayoutTag, NpuArch::layout::VectorLayout> || | ||
| 440 | + std::is_same_v<LayoutTag, NpuArch::layout::zN> || | ||
| 441 | + std::is_same_v<LayoutTag, NpuArch::layout::nZ> || | ||
| 442 | + std::is_same_v<LayoutTag, NpuArch::layout::zZ>, | ||
| 443 | + "Unsupported LayoutTag for MakeLayoutFromTag, only support NpuArch::layout::RowMajor or" | ||
| 444 | + "NpuArch::layout::ColumnMajor or NpuArch::layout::zN or NpuArch::layout::nZ or NpuArch::layout::zZ"); | ||
| 445 | + | ||
| 446 | + constexpr uint32_t ELE_NUM_PER_C0 = NpuArch::BYTE_PER_C0 / sizeof(Element); | ||
| 447 | + constexpr uint32_t ELE_NUM_PER_FRACTAL = NpuArch::BYTE_PER_FRACTAL / sizeof(Element); | ||
| 448 | + | ||
| 449 | + if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::VectorLayout>) { | ||
| 450 | + return MakeLayout(MakeShape(cols), MakeStride(Int<1>{})); | ||
| 451 | + } else if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::RowMajor>) { | ||
| 452 | + return MakeLayout(MakeShape(rows, cols), MakeStride((int64_t)cols, Int<1>{})); | ||
| 453 | + } else if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::ColumnMajor>) { | ||
| 454 | + return MakeLayout(MakeShape(rows, cols), MakeStride(Int<1>{}, (int64_t)rows)); | ||
| 455 | + } else if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::zN>) { | ||
| 456 | + return MakeLayout( | ||
| 457 | + MakeShape(MakeShape(Int<NpuArch::C0_NUM_PER_FRACTAL>{}, CeilDiv(rows, Int<NpuArch::C0_NUM_PER_FRACTAL>{})), | ||
| 458 | + MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(cols, Int<ELE_NUM_PER_C0>{}))), | ||
| 459 | + MakeStride(MakeStride(Int<ELE_NUM_PER_C0>{}, Int<ELE_NUM_PER_FRACTAL>{}), | ||
| 460 | + MakeStride(Int<1>{}, RoundUp((int64_t)rows, Int<NpuArch::C0_NUM_PER_FRACTAL>{}) * ELE_NUM_PER_C0))); | ||
| 461 | + } else if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::zZ>) { | ||
| 462 | + return MakeLayout( | ||
| 463 | + MakeShape(MakeShape(Int<NpuArch::C0_NUM_PER_FRACTAL>{}, CeilDiv(rows, Int<NpuArch::C0_NUM_PER_FRACTAL>{})), | ||
| 464 | + MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(cols, Int<ELE_NUM_PER_C0>{}))), | ||
| 465 | + MakeStride(MakeStride(Int<ELE_NUM_PER_C0>{}, | ||
| 466 | + RoundUp((int64_t)cols, Int<ELE_NUM_PER_C0>{}) * NpuArch::C0_NUM_PER_FRACTAL), | ||
| 467 | + MakeStride(Int<1>{}, Int<ELE_NUM_PER_FRACTAL>{}))); | ||
| 468 | + } else { | ||
| 469 | + return MakeLayout( | ||
| 470 | + MakeShape(MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(rows, Int<ELE_NUM_PER_C0>{})), | ||
| 471 | + MakeShape(Int<NpuArch::C0_NUM_PER_FRACTAL>{}, CeilDiv(cols, Int<NpuArch::C0_NUM_PER_FRACTAL>{}))), | ||
| 472 | + MakeStride( | ||
| 473 | + MakeStride(Int<1>{}, RoundUp((int64_t)cols, Int<NpuArch::C0_NUM_PER_FRACTAL>{}) * ELE_NUM_PER_C0), | ||
| 474 | + MakeStride(Int<ELE_NUM_PER_C0>{}, Int<ELE_NUM_PER_FRACTAL>{}))); | ||
| 475 | + } | ||
| 476 | +} | ||
| 477 | + | ||
| 478 | +// Make a MxScale layout with Rows and Cols. | ||
| 479 | +template <class Element, class LayoutTag, bool isMxScaleB, class T, class U> | ||
| 480 | +HOST_DEVICE constexpr | ||
| 481 | +auto MakeMxScaleLayout(T const& rows, U const& cols) | ||
| 482 | +{ | ||
| 483 | + static_assert( | ||
| 484 | + std::is_same_v<Element, AscendC::fp8_e8m0_t> && | ||
| 485 | + (std::is_same_v<LayoutTag, NpuArch::layout::RowMajor> || | ||
| 486 | + std::is_same_v<LayoutTag, NpuArch::layout::ColumnMajor> || | ||
| 487 | + std::is_same_v<LayoutTag, NpuArch::layout::zZ> || std::is_same_v<LayoutTag, NpuArch::layout::nN>), | ||
| 488 | + "only support RowMajor, ColumnMajor, zZ, nN in fp8_e8m0_t dtype" | ||
| 489 | + ); | ||
| 490 | + | ||
| 491 | + constexpr uint32_t ELE_NUM_PER_C0 = 2; | ||
| 492 | + constexpr uint32_t ELE_NUM_PER_FRACTAL = 32; | ||
| 493 | + | ||
| 494 | + if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::RowMajor>) { | ||
| 495 | + if constexpr (!isMxScaleB) { | ||
| 496 | + return MakeLayout( | ||
| 497 | + MakeShape(rows, MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(cols, Int<ELE_NUM_PER_C0>{}))), | ||
| 498 | + MakeStride(RoundUp(cols, Int<ELE_NUM_PER_C0>{}), MakeStride(Int<1>{}, Int<ELE_NUM_PER_C0>{})) | ||
| 499 | + ); | ||
| 500 | + } else { | ||
| 501 | + return MakeLayout( | ||
| 502 | + MakeShape(MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(rows, Int<ELE_NUM_PER_C0>{})), cols), | ||
| 503 | + MakeStride(MakeStride(Int<1>{}, cols * ELE_NUM_PER_C0), Int<ELE_NUM_PER_C0>{}) | ||
| 504 | + ); | ||
| 505 | + } | ||
| 506 | + } else if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::ColumnMajor>) { | ||
| 507 | + if constexpr (!isMxScaleB) { | ||
| 508 | + return MakeLayout( | ||
| 509 | + MakeShape(rows, MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(cols, Int<ELE_NUM_PER_C0>{}))), | ||
| 510 | + MakeStride(Int<ELE_NUM_PER_C0>{}, MakeStride(Int<1>{}, rows * ELE_NUM_PER_C0)) | ||
| 511 | + ); | ||
| 512 | + } else { | ||
| 513 | + return MakeLayout( | ||
| 514 | + MakeShape(MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(rows, Int<ELE_NUM_PER_C0>{})), cols), | ||
| 515 | + MakeStride(MakeStride(Int<1>{}, Int<ELE_NUM_PER_C0>{}), RoundUp(rows, Int<ELE_NUM_PER_C0>{})) | ||
| 516 | + ); | ||
| 517 | + } | ||
| 518 | + } else if constexpr (std::is_same_v<LayoutTag, NpuArch::layout::zZ>) { | ||
| 519 | + return MakeLayout( | ||
| 520 | + MakeShape( | ||
| 521 | + MakeShape(Int<NpuArch::C0_NUM_PER_FRACTAL>{}, CeilDiv(rows, Int<NpuArch::C0_NUM_PER_FRACTAL>{})), | ||
| 522 | + MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(cols, Int<ELE_NUM_PER_C0>{})) | ||
| 523 | + ), | ||
| 524 | + MakeStride( | ||
| 525 | + MakeStride( | ||
| 526 | + Int<ELE_NUM_PER_C0>{}, RoundUp((int64_t)cols, Int<ELE_NUM_PER_C0>{}) * NpuArch::C0_NUM_PER_FRACTAL | ||
| 527 | + ), | ||
| 528 | + MakeStride(Int<1>{}, Int<ELE_NUM_PER_FRACTAL>{}) | ||
| 529 | + ) | ||
| 530 | + ); | ||
| 531 | + } else { | ||
| 532 | + return MakeLayout( | ||
| 533 | + MakeShape( | ||
| 534 | + MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(rows, Int<ELE_NUM_PER_C0>{})), | ||
| 535 | + MakeShape(Int<NpuArch::C0_NUM_PER_FRACTAL>{}, CeilDiv(cols, Int<NpuArch::C0_NUM_PER_FRACTAL>{})) | ||
| 536 | + ), | ||
| 537 | + MakeStride( | ||
| 538 | + MakeStride(Int<1>{}, Int<ELE_NUM_PER_FRACTAL>{}), | ||
| 539 | + MakeStride( | ||
| 540 | + Int<ELE_NUM_PER_C0>{}, RoundUp((int64_t)rows, Int<ELE_NUM_PER_C0>{}) * NpuArch::C0_NUM_PER_FRACTAL | ||
| 541 | + ) | ||
| 542 | + ) | ||
| 543 | + ); | ||
| 544 | + } | ||
| 545 | +} | ||
| 546 | + | ||
| 547 | +template <class Layout, class ShapeNew> | ||
| 548 | +HOST_DEVICE constexpr | ||
| 549 | +auto MakeLayoutTile(Layout const& layout, ShapeNew const& shapeNew) | ||
| 550 | +{ | ||
| 551 | + static_assert( | ||
| 552 | + is_tuple<ShapeNew>::value && depth_v<ShapeNew> == 1 && (rank_v<ShapeNew> == 1 || rank_v<ShapeNew> == 2) | ||
| 553 | + ); | ||
| 554 | + | ||
| 555 | + if constexpr (Layout::depth == 1 && (Layout::rank == 1 || Layout::rank == 2)) { | ||
| 556 | + return MakeLayout(shapeNew, layout.stride()); | ||
| 557 | + } else if constexpr (Layout::depth == 2 && Layout::rank == 2 && rank_v<decltype(shape<0>(Layout{}))> == 1 && | ||
| 558 | + rank_v<decltype(shape<1>(Layout{}))> == 2) { | ||
| 559 | + const uint32_t rows = get<0>(shapeNew); | ||
| 560 | + const uint32_t cols = get<1>(shapeNew); | ||
| 561 | + constexpr uint32_t ELE_NUM_PER_C0 = decltype(shape<1, 0>(layout))::value; | ||
| 562 | + return MakeLayout( | ||
| 563 | + MakeShape(rows, MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(cols, Int<ELE_NUM_PER_C0>{}))), | ||
| 564 | + layout.stride() | ||
| 565 | + ); | ||
| 566 | + } else if constexpr (Layout::depth == 2 && Layout::rank == 2 && rank_v<decltype(shape<0>(Layout{}))> == 2 && | ||
| 567 | + rank_v<decltype(shape<1>(Layout{}))> == 1) { | ||
| 568 | + const uint32_t rows = get<0>(shapeNew); | ||
| 569 | + const uint32_t cols = get<1>(shapeNew); | ||
| 570 | + constexpr uint32_t ELE_NUM_PER_C0 = decltype(shape<0, 0>(layout))::value; | ||
| 571 | + return MakeLayout( | ||
| 572 | + MakeShape(MakeShape(Int<ELE_NUM_PER_C0>{}, CeilDiv(rows, Int<ELE_NUM_PER_C0>{})), cols), | ||
| 573 | + layout.stride() | ||
| 574 | + ); | ||
| 575 | + } else if constexpr (is_static<decltype(shape<0, 0>(layout))>::value && | ||
| 576 | + is_static<decltype(shape<1, 0>(layout))>::value) { | ||
| 577 | + const uint32_t rows = get<0>(shapeNew); | ||
| 578 | + const uint32_t cols = get<1>(shapeNew); | ||
| 579 | + constexpr uint32_t dstInnerShapeRow = decltype(shape<0, 0>(layout))::value; | ||
| 580 | + constexpr uint32_t dstInnerShapeCol = decltype(shape<1, 0>(layout))::value; | ||
| 581 | + return MakeLayout( | ||
| 582 | + MakeShape(MakeShape(Int<dstInnerShapeRow>{}, CeilDiv<dstInnerShapeRow>(rows)), | ||
| 583 | + MakeShape(Int<dstInnerShapeCol>{}, CeilDiv<dstInnerShapeCol>(cols))), | ||
| 584 | + layout.stride()); | ||
| 585 | + } else { | ||
| 586 | + const uint32_t rows = get<0>(shapeNew); | ||
| 587 | + const uint32_t cols = get<1>(shapeNew); | ||
| 588 | + const uint32_t dstInnerShapeRow = shape<0, 0>(layout); | ||
| 589 | + const uint32_t dstInnerShapeCol = shape<1, 0>(layout); | ||
| 590 | + return MakeLayout( | ||
| 591 | + MakeShape(MakeShape(dstInnerShapeRow, CeilDiv(rows, dstInnerShapeRow)), | ||
| 592 | + MakeShape(dstInnerShapeCol, CeilDiv(cols, dstInnerShapeCol))), | ||
| 593 | + layout.stride()); | ||
| 594 | + } | ||
| 595 | +} | ||
| 596 | + | ||
| 597 | +template <class T, class U> | ||
| 598 | +HOST_DEVICE constexpr | ||
| 599 | +auto MakeLayoutL0C(T const& rows, U const& cols) | ||
| 600 | +{ | ||
| 601 | + constexpr uint32_t ELE_NUM_PER_FRACTAL = 256; | ||
| 602 | + return MakeLayout( | ||
| 603 | + MakeShape(MakeShape(Int<NpuArch::C0_NUM_PER_FRACTAL>{}, CeilDiv(rows, Int<NpuArch::C0_NUM_PER_FRACTAL>{})), | ||
| 604 | + MakeShape(Int<NpuArch::C0_NUM_PER_FRACTAL>{}, CeilDiv(cols, Int<NpuArch::C0_NUM_PER_FRACTAL>{}))), | ||
| 605 | + MakeStride(MakeStride(Int<NpuArch::C0_NUM_PER_FRACTAL>{}, Int<ELE_NUM_PER_FRACTAL>{}), | ||
| 606 | + MakeStride( | ||
| 607 | + Int<1>{}, RoundUp((int64_t)rows, Int<NpuArch::C0_NUM_PER_FRACTAL>{}) * NpuArch::C0_NUM_PER_FRACTAL))); | ||
| 608 | +} | ||
| 609 | + | ||
| 610 | +} // end namespace tla | ||
| 611 | + | ||
| 612 | + | ||
| @@ -0,0 +1,68 @@ | |||
| 1 | +/** | ||
| 2 | + * This program is free software, you can redistribute it and/or modify. | ||
| 3 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 4 | + * This file is a part of the CANN Open Software. | ||
| 5 | + * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace tla { | ||
| 18 | + | ||
| 19 | +template <typename T, T... Ns> | ||
| 20 | +struct IntegerSequence { | ||
| 21 | + using value_type = T; | ||
| 22 | + static constexpr size_t size() { return sizeof...(Ns); } | ||
| 23 | +}; | ||
| 24 | + | ||
| 25 | +template <typename Sequence, typename T, size_t N> | ||
| 26 | +struct MakeIntegerSequenceImpl; | ||
| 27 | + | ||
| 28 | +template <typename T, size_t... Ns> | ||
| 29 | +struct MakeIntegerSequenceImpl<IntegerSequence<T, Ns...>, T, 0> { | ||
| 30 | + typedef IntegerSequence<T, Ns...> type; | ||
| 31 | +}; | ||
| 32 | + | ||
| 33 | +template <typename T, size_t N, size_t... Ns> | ||
| 34 | +struct MakeIntegerSequenceImpl<IntegerSequence<T, Ns...>, T, N> { | ||
| 35 | + typedef typename MakeIntegerSequenceImpl<IntegerSequence<T, N - 1, Ns...>, T, N - 1>::type type; | ||
| 36 | +}; | ||
| 37 | + | ||
| 38 | +template <typename T, T N> | ||
| 39 | +using MakeIntegerSequence = typename MakeIntegerSequenceImpl<IntegerSequence<T>, T, N>::type; | ||
| 40 | + | ||
| 41 | + | ||
| 42 | +// index_sequence | ||
| 43 | +template <size_t... Ints> | ||
| 44 | +using index_sequence = IntegerSequence<size_t, Ints...>; | ||
| 45 | + | ||
| 46 | +template <size_t N> | ||
| 47 | +using make_index_sequence = MakeIntegerSequence<size_t, N>; | ||
| 48 | + | ||
| 49 | +// int_sequence | ||
| 50 | +template <int... Ints> | ||
| 51 | +using int_sequence = IntegerSequence<int, Ints...>; | ||
| 52 | + | ||
| 53 | +template <int N> | ||
| 54 | +using make_int_sequence = MakeIntegerSequence<int, N>; | ||
| 55 | + | ||
| 56 | +// Shortcuts | ||
| 57 | +template <int... Ints> | ||
| 58 | +using seq = int_sequence<Ints...>; | ||
| 59 | + | ||
| 60 | +template <int N> | ||
| 61 | +using make_seq = make_int_sequence<N>; | ||
| 62 | + | ||
| 63 | +template <class Tuple> | ||
| 64 | +using tuple_seq = make_seq<tuple_size<tla::remove_cvref_t<Tuple>>::value>; | ||
| 65 | + | ||
| 66 | +} // end namespace tla | ||
| 67 | + | ||
| 68 | + | ||
| @@ -0,0 +1,172 @@ | |||
| 1 | +/** | ||
| 2 | + * This program is free software, you can redistribute it and/or modify. | ||
| 3 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 4 | + * This file is a part of the CANN Open Software. | ||
| 5 | + * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +namespace tla { | ||
| 19 | + | ||
| 20 | +// A constant value: short name and type-deduction for fast compilation | ||
| 21 | +template <auto v> | ||
| 22 | +struct C { | ||
| 23 | + using type = C<v>; | ||
| 24 | + static constexpr auto value = v; | ||
| 25 | + using value_type = decltype(v); | ||
| 26 | + HOST_DEVICE constexpr operator value_type() const noexcept { return value; } | ||
| 27 | + HOST_DEVICE constexpr value_type operator()() const noexcept { return value; } | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | +// Deprecate | ||
| 31 | +template <class T, T v> | ||
| 32 | +using constant = C<v>; | ||
| 33 | + | ||
| 34 | +template <bool b> | ||
| 35 | +using bool_constant = C<b>; | ||
| 36 | + | ||
| 37 | +using true_type = bool_constant<true>; | ||
| 38 | +using false_type = bool_constant<false>; | ||
| 39 | + | ||
| 40 | +template <class T> | ||
| 41 | +using is_std_integral = std::is_integral<T>; | ||
| 42 | + | ||
| 43 | +// A more std:: conforming integral_constant that enforces type but interops with C<v> | ||
| 44 | +template <class T, T v> | ||
| 45 | +struct integral_constant : C<v> { | ||
| 46 | + using type = integral_constant<T, v>; | ||
| 47 | + static constexpr T value = v; | ||
| 48 | + using value_type = T; | ||
| 49 | + HOST_DEVICE constexpr value_type operator()() const noexcept { return value; } | ||
| 50 | +}; | ||
| 51 | + | ||
| 52 | +// Use tla::is_std_integral<T> to match built-in integral types (int, int64_t, unsigned, etc) | ||
| 53 | +// Use tla::is_integral<T> to match both built-in integral types AND static integral types. | ||
| 54 | + | ||
| 55 | +template <class T> | ||
| 56 | +struct is_integral : bool_constant<is_std_integral<T>::value> {}; | ||
| 57 | +template <auto v> | ||
| 58 | +struct is_integral<C<v> > : true_type {}; | ||
| 59 | +template <class T, T v> | ||
| 60 | +struct is_integral<integral_constant<T, v>> : true_type {}; | ||
| 61 | + | ||
| 62 | +// is_static detects if an (abstract) value is defined completely by its type (no members) | ||
| 63 | +template <class T> | ||
| 64 | +struct is_static : bool_constant<std::is_empty<remove_cvref_t<T>>::value> {}; | ||
| 65 | + | ||
| 66 | +// is_constant detects if a type is a static integral type and if v is equal to a value | ||
| 67 | + | ||
| 68 | +template <auto n, class T> | ||
| 69 | +struct is_constant : false_type {}; | ||
| 70 | +template <auto n, class T> | ||
| 71 | +struct is_constant<n, T const > : is_constant<n, T> {}; | ||
| 72 | +template <auto n, class T> | ||
| 73 | +struct is_constant<n, T const&> : is_constant<n, T> {}; | ||
| 74 | +template <auto n, class T> | ||
| 75 | +struct is_constant<n, T &> : is_constant<n, T> {}; | ||
| 76 | +template <auto n, class T> | ||
| 77 | +struct is_constant<n, T &&> : is_constant<n, T> {}; | ||
| 78 | +template <auto n, auto v> | ||
| 79 | +struct is_constant<n, C<v> > : bool_constant<v == n> {}; | ||
| 80 | +template <auto n, class T, T v> | ||
| 81 | +struct is_constant<n, integral_constant<T, v>> : bool_constant<v == n> {}; | ||
| 82 | + | ||
| 83 | +// | ||
| 84 | +// Specializations | ||
| 85 | +// | ||
| 86 | + | ||
| 87 | +template <int v> | ||
| 88 | +using Int = C<v>; | ||
| 89 | +using _0 = Int<0>; | ||
| 90 | +using _64 = Int<64>; | ||
| 91 | +using _128 = Int<128>; | ||
| 92 | +using _256 = Int<256>; | ||
| 93 | +using _512 = Int<512>; | ||
| 94 | + | ||
| 95 | +/***************/ | ||
| 96 | +/** Operators **/ | ||
| 97 | +/***************/ | ||
| 98 | + | ||
| 99 | + | ||
| 100 | + template <auto t> \ | ||
| 101 | + HOST_DEVICE constexpr \ | ||
| 102 | + C<(OP t)> operator OP (C<t>) { \ | ||
| 103 | + return {}; \ | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + template <auto t, auto u> \ | ||
| 107 | + HOST_DEVICE constexpr \ | ||
| 108 | + C<(t OP u)> operator OP (C<t>, C<u>) { \ | ||
| 109 | + return {}; \ | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | +TLA_LEFT_UNARY_OP(+); | ||
| 113 | +TLA_LEFT_UNARY_OP(-); | ||
| 114 | +TLA_LEFT_UNARY_OP(~); | ||
| 115 | +TLA_LEFT_UNARY_OP(!); | ||
| 116 | +TLA_LEFT_UNARY_OP(*); | ||
| 117 | + | ||
| 118 | +TLA_BINARY_OP(+); | ||
| 119 | +TLA_BINARY_OP(-); | ||
| 120 | +TLA_BINARY_OP(*); | ||
| 121 | +TLA_BINARY_OP(/); | ||
| 122 | +TLA_BINARY_OP(%); | ||
| 123 | +TLA_BINARY_OP(&); | ||
| 124 | +TLA_BINARY_OP(|); | ||
| 125 | +TLA_BINARY_OP(^); | ||
| 126 | +TLA_BINARY_OP(<<); | ||
| 127 | +TLA_BINARY_OP(>>); | ||
| 128 | + | ||
| 129 | + | ||
| 130 | + | ||
| 131 | + | ||
| 132 | + | ||
| 133 | +// | ||
| 134 | +// Named functions from math.hpp | ||
| 135 | +// | ||
| 136 | + | ||
| 137 | + | ||
| 138 | + template <auto t> \ | ||
| 139 | + HOST_DEVICE constexpr \ | ||
| 140 | + auto OP (C<t>) { \ | ||
| 141 | + return C<OP(t)>{}; \ | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + template <auto t, auto u> \ | ||
| 145 | + HOST_DEVICE constexpr \ | ||
| 146 | + auto OP (C<t>, C<u>) { \ | ||
| 147 | + return C<OP(t, u)>{}; \ | ||
| 148 | + } \ | ||
| 149 | + template <auto t, class U, \ | ||
| 150 | + TLA_REQUIRES(is_std_integral<U>::value)> \ | ||
| 151 | + HOST_DEVICE constexpr \ | ||
| 152 | + auto OP (C<t>, U u) { \ | ||
| 153 | + return OP(t, u); \ | ||
| 154 | + } \ | ||
| 155 | + template <class T, auto u, \ | ||
| 156 | + TLA_REQUIRES(is_std_integral<T>::value)> \ | ||
| 157 | + HOST_DEVICE constexpr \ | ||
| 158 | + auto OP (T t, C<u>) { \ | ||
| 159 | + return OP(t, u); \ | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | +TLA_NAMED_BINARY_FN(max); | ||
| 163 | +TLA_NAMED_BINARY_FN(min); | ||
| 164 | +TLA_NAMED_BINARY_FN(add); | ||
| 165 | + | ||
| 166 | + | ||
| 167 | + | ||
| 168 | + | ||
| 169 | + | ||
| 170 | +} // end namespace tla | ||
| 171 | + | ||
| 172 | + | ||
| @@ -0,0 +1,52 @@ | |||
| 1 | +/** | ||
| 2 | + * This program is free software, you can redistribute it and/or modify. | ||
| 3 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 4 | + * This file is a part of the CANN Open Software. | ||
| 5 | + * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace tla { | ||
| 18 | + | ||
| 19 | +// | ||
| 20 | +// Common Operations | ||
| 21 | +// | ||
| 22 | + | ||
| 23 | +template <class T, class U, | ||
| 24 | + TLA_REQUIRES(std::is_arithmetic<T>::value && | ||
| 25 | + std::is_arithmetic<U>::value)> | ||
| 26 | +HOST_DEVICE constexpr | ||
| 27 | +auto | ||
| 28 | +max(T const& t, U const& u) { | ||
| 29 | + return t < u ? u : t; | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +template <class T, class U, | ||
| 33 | + TLA_REQUIRES(std::is_arithmetic<T>::value && | ||
| 34 | + std::is_arithmetic<U>::value)> | ||
| 35 | +HOST_DEVICE constexpr | ||
| 36 | +auto | ||
| 37 | +min(T const& t, U const& u) { | ||
| 38 | + return t < u ? t : u; | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +template <class T, class U, | ||
| 42 | + TLA_REQUIRES(std::is_arithmetic<T>::value && | ||
| 43 | + std::is_arithmetic<U>::value)> | ||
| 44 | +HOST_DEVICE constexpr | ||
| 45 | +auto | ||
| 46 | +add(T const& t, U const& u) { | ||
| 47 | + return t + u; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +} // namespace tla | ||
| 51 | + | ||
| 52 | + | ||
| @@ -0,0 +1,117 @@ | |||
| 1 | +/** | ||
| 2 | + * This program is free software, you can redistribute it and/or modify. | ||
| 3 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 4 | + * This file is a part of the CANN Open Software. | ||
| 5 | + * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace tla { | ||
| 20 | +// | ||
| 21 | +// Tensor | ||
| 22 | +// | ||
| 23 | + | ||
| 24 | +template <class BuiltinTensor, class Layout_, class Coord_, AscendC::TPosition Position> | ||
| 25 | +struct Tensor { | ||
| 26 | + using Element = typename BuiltinTensor::PrimType; | ||
| 27 | + using Layout = Layout_; | ||
| 28 | + using Coord = Coord_; | ||
| 29 | + static constexpr AscendC::TPosition position = Position; | ||
| 30 | + | ||
| 31 | + HOST_DEVICE constexpr | ||
| 32 | + Tensor() {} | ||
| 33 | + | ||
| 34 | + HOST_DEVICE constexpr | ||
| 35 | + Tensor(BuiltinTensor const& builtinTensor, Layout const& layout, Coord const& coord = {}) | ||
| 36 | + : rep_(builtinTensor, layout, coord) {} | ||
| 37 | + | ||
| 38 | + // | ||
| 39 | + // Accessors | ||
| 40 | + // | ||
| 41 | + | ||
| 42 | + static constexpr int rank = Layout::rank; | ||
| 43 | + | ||
| 44 | + HOST_DEVICE constexpr | ||
| 45 | + decltype(auto) tensor() const | ||
| 46 | + { | ||
| 47 | + return *this; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + HOST_DEVICE constexpr | ||
| 51 | + decltype(auto) data() const | ||
| 52 | + { | ||
| 53 | + return get<0>(rep_); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + HOST_DEVICE constexpr | ||
| 57 | + decltype(auto) data() | ||
| 58 | + { | ||
| 59 | + return get<0>(rep_); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + HOST_DEVICE constexpr | ||
| 63 | + decltype(auto) layout() const | ||
| 64 | + { | ||
| 65 | + return get<1>(rep_); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + HOST_DEVICE constexpr | ||
| 69 | + decltype(auto) coord() const | ||
| 70 | + { | ||
| 71 | + return get<2>(rep_); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + HOST_DEVICE constexpr | ||
| 75 | + decltype(auto) shape() const | ||
| 76 | + { | ||
| 77 | + return layout().shape(); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + HOST_DEVICE constexpr | ||
| 81 | + decltype(auto) stride() const | ||
| 82 | + { | ||
| 83 | + return layout().stride(); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + tla::tuple<BuiltinTensor, Layout, Coord> rep_; | ||
| 87 | +}; | ||
| 88 | + | ||
| 89 | +template <class BuiltinTensor, class Layout, class PositionType> | ||
| 90 | +HOST_DEVICE constexpr | ||
| 91 | +auto MakeTensor(BuiltinTensor const& builtinTensor, Layout const& layout, PositionType) | ||
| 92 | +{ | ||
| 93 | + using Coord = detail::MakeZeroTuple<Layout::rank>; | ||
| 94 | + return Tensor<BuiltinTensor, Layout, Coord, PositionType::value>(builtinTensor, layout); | ||
| 95 | +} | ||
| 96 | + | ||
| 97 | +template <class BuiltinTensor, class Layout, class Coord, class PositionType> | ||
| 98 | +HOST_DEVICE constexpr | ||
| 99 | +auto MakeTensor(BuiltinTensor const& builtinTensor, Layout const& layout, Coord const& coord, PositionType) | ||
| 100 | +{ | ||
| 101 | + return Tensor<BuiltinTensor, Layout, Coord, PositionType::value>(builtinTensor, layout, coord); | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +template <class Tensor, class Coord, class Shape> | ||
| 105 | +__aicore__ inline constexpr | ||
| 106 | +auto GetTile(Tensor const& tensor, Coord const& coord, Shape const& shape) | ||
| 107 | +{ | ||
| 108 | + auto layout = tensor.layout(); | ||
| 109 | + auto builtinTensor = tensor.data(); | ||
| 110 | + auto layoutNew = MakeLayoutTile(layout, shape); | ||
| 111 | + auto coordNew = Add(tensor.coord(), coord); | ||
| 112 | + return MakeTensor(builtinTensor, layoutNew, coordNew, NpuArch::Arch::PositionType<Tensor::position>{}); | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +} // end namespace tla | ||
| 116 | + | ||
| 117 | + | ||
| @@ -0,0 +1,151 @@ | |||
| 1 | +/** | ||
| 2 | + * This program is free software, you can redistribute it and/or modify. | ||
| 3 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 4 | + * This file is a part of the CANN Open Software. | ||
| 5 | + * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace tla { | ||
| 18 | + | ||
| 19 | +namespace detail { | ||
| 20 | + | ||
| 21 | +// EBO stands for "empty base optimization." | ||
| 22 | +template <size_t N, class T, bool IsEmpty = std::is_empty<T>::value> | ||
| 23 | +struct EBO; | ||
| 24 | + | ||
| 25 | +// Specialization for types T that are empty; | ||
| 26 | +template <size_t N, class T> | ||
| 27 | +struct EBO<N, T, true> { | ||
| 28 | + HOST_DEVICE constexpr | ||
| 29 | + EBO() {} | ||
| 30 | + | ||
| 31 | + HOST_DEVICE constexpr | ||
| 32 | + EBO(T const&) {} | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +template <size_t N, class T> | ||
| 36 | +HOST_DEVICE constexpr | ||
| 37 | +T getv(EBO<N, T, true> const&) | ||
| 38 | +{ | ||
| 39 | + return {}; | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +// Specialization for types T that are not empty; | ||
| 43 | +template <size_t N, class T> | ||
| 44 | +struct EBO<N, T, false> { | ||
| 45 | + HOST_DEVICE constexpr | ||
| 46 | + EBO() : t_{} {} | ||
| 47 | + | ||
| 48 | + HOST_DEVICE constexpr | ||
| 49 | + EBO(T const& t) : t_{t} {} | ||
| 50 | + | ||
| 51 | + T t_; | ||
| 52 | +}; | ||
| 53 | + | ||
| 54 | +template <size_t N, class T> | ||
| 55 | +HOST_DEVICE constexpr | ||
| 56 | +T const& getv(EBO<N, T, false> const& x) | ||
| 57 | +{ | ||
| 58 | + return x.t_; | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +template <size_t N, class T> | ||
| 62 | +HOST_DEVICE constexpr | ||
| 63 | +T& getv(EBO<N, T, false>& x) | ||
| 64 | +{ | ||
| 65 | + return x.t_; | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +// TupleBase | ||
| 69 | +template <class IdxSeq, class... T> | ||
| 70 | +struct TupleBase; | ||
| 71 | + | ||
| 72 | +template <size_t... I, class... T> | ||
| 73 | +struct TupleBase<index_sequence<I...>, T...> : EBO<I, T>... { | ||
| 74 | + HOST_DEVICE constexpr | ||
| 75 | + TupleBase() {} | ||
| 76 | + | ||
| 77 | + HOST_DEVICE constexpr | ||
| 78 | + TupleBase(T const&... t) : EBO<I, T>(t)... {} | ||
| 79 | +}; | ||
| 80 | + | ||
| 81 | +} // end namespace detail | ||
| 82 | + | ||
| 83 | +// tla::tuple class. | ||
| 84 | +template <class... T> | ||
| 85 | +struct tuple : detail::TupleBase<make_index_sequence<sizeof...(T)>, T...> { | ||
| 86 | + HOST_DEVICE constexpr | ||
| 87 | + tuple() {} | ||
| 88 | + | ||
| 89 | + HOST_DEVICE constexpr | ||
| 90 | + tuple(T const&... t) : detail::TupleBase<make_index_sequence<sizeof...(T)>, T...>(t...) {} | ||
| 91 | +}; | ||
| 92 | + | ||
| 93 | +template <> | ||
| 94 | +struct tuple<> {}; | ||
| 95 | + | ||
| 96 | +// get for tla::tuple | ||
| 97 | +template <size_t I, class... T> | ||
| 98 | +HOST_DEVICE constexpr | ||
| 99 | +decltype(auto) get(tuple<T...> const& t) noexcept | ||
| 100 | +{ | ||
| 101 | + static_assert(I < sizeof...(T), "Index out of range"); | ||
| 102 | + return detail::getv<I>(t); | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +template <size_t I, class... T> | ||
| 106 | +HOST_DEVICE constexpr | ||
| 107 | +decltype(auto) get(tuple<T...>& t) noexcept | ||
| 108 | +{ | ||
| 109 | + static_assert(I < sizeof...(T), "Index out of range"); | ||
| 110 | + return detail::getv<I>(t); | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | +template <size_t I, class... T> | ||
| 114 | +HOST_DEVICE constexpr | ||
| 115 | +decltype(auto) get(tuple<T...>&& t) noexcept | ||
| 116 | +{ | ||
| 117 | + static_assert(I < sizeof...(T), "Index out of range"); | ||
| 118 | + return detail::getv<I>(static_cast<tuple<T...>&&>(t)); | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +namespace detail { | ||
| 122 | + | ||
| 123 | +template <class T> | ||
| 124 | +auto has_tuple_size(T*) -> bool_constant<(0 <= tuple_size<T>::value)>; | ||
| 125 | +auto has_tuple_size(...) -> false_type; | ||
| 126 | + | ||
| 127 | +} // end namespace detail | ||
| 128 | + | ||
| 129 | +template <class T> | ||
| 130 | +struct is_tuple : decltype(detail::has_tuple_size((T*)0)) {}; | ||
| 131 | + | ||
| 132 | +template <class... T> | ||
| 133 | +struct tuple_size<tla::tuple<T...>> | ||
| 134 | + : std::integral_constant<size_t, sizeof...(T)> {}; | ||
| 135 | + | ||
| 136 | +template <class... T> | ||
| 137 | +struct tuple_size<const tla::tuple<T...>> | ||
| 138 | + : std::integral_constant<size_t, sizeof...(T)> {}; | ||
| 139 | + | ||
| 140 | +// make_tuple | ||
| 141 | +template <class... T> | ||
| 142 | +HOST_DEVICE constexpr | ||
| 143 | +tuple<T...> | ||
| 144 | +MakeTuple(T const&... t) | ||
| 145 | +{ | ||
| 146 | + return {t...}; | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +} // end namespace tla | ||
| 150 | + | ||
| 151 | + | ||
| @@ -0,0 +1,50 @@ | |||
| 1 | +/** | ||
| 2 | + * This program is free software, you can redistribute it and/or modify. | ||
| 3 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 4 | + * This file is a part of the CANN Open Software. | ||
| 5 | + * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +namespace tla { | ||
| 25 | + | ||
| 26 | +// using std::remove_cvref; | ||
| 27 | +template <class T> | ||
| 28 | +struct remove_cvref { | ||
| 29 | + using type = std::remove_cv_t<std::remove_reference_t<T>>; | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +// using std::remove_cvref_t; | ||
| 33 | +template <class T> | ||
| 34 | +using remove_cvref_t = typename remove_cvref<T>::type; | ||
| 35 | + | ||
| 36 | + | ||
| 37 | +// tuple_size, tuple_element | ||
| 38 | +template <class T, class = void> | ||
| 39 | +struct tuple_size; | ||
| 40 | + | ||
| 41 | +template <class T> | ||
| 42 | +struct tuple_size<T, std::void_t<typename std::tuple_size<T>::type>> | ||
| 43 | + : std::integral_constant<size_t, std::tuple_size<T>::value> {}; | ||
| 44 | + | ||
| 45 | +template <class T> | ||
| 46 | +constexpr size_t tuple_size_v = tuple_size<T>::value; | ||
| 47 | + | ||
| 48 | +} // end namespace tla | ||
| 49 | + | ||
| 50 | + | ||