已合并
【社区任务】Add roll operator #3333
boxw987创建于 6月15日
【社区任务】Add roll operator #3333
已合并
共 23 个文件变更+2772-0
| @@ -0,0 +1,11 @@ | |||
| 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 | +add_all_modules_sources(OPTYPE roll ACLNNTYPE aclnn_exclude) | ||
| @@ -0,0 +1,55 @@ | |||
| 1 | +# Roll | ||
| 2 | + | ||
| 3 | +## 贡献说明 | ||
| 4 | + | ||
| 5 | +| 贡献者 | 贡献方 | 贡献算子 | 贡献时间 | 贡献内容 | | ||
| 6 | +| --- | --- | --- | --- | --- | | ||
| 7 | +| boxw987 | 个人开发者 | Roll | 2026/06 | Roll 算子适配开源仓 | | ||
| 8 | + | ||
| 9 | +## 支持的产品型号 | ||
| 10 | + | ||
| 11 | +- Atlas A2 训练系列产品 | ||
| 12 | + | ||
| 13 | +## 算子描述 | ||
| 14 | + | ||
| 15 | +- 功能描述 | ||
| 16 | + | ||
| 17 | + `Roll` 沿给定维度对输入张量执行循环位移;当 `dims` 为空时,先按逻辑视图展平,再执行一维循环位移,最后按原始形状输出。 | ||
| 18 | + | ||
| 19 | +- 原型信息 | ||
| 20 | + | ||
| 21 | + <table> | ||
| 22 | + <tr><th align="center">算子类型(OpType)</th><th colspan="4" align="center">Roll</th></tr> | ||
| 23 | + <tr><td align="center"> </td><td align="center">name</td><td align="center">Type</td><td align="center">data type</td><td align="center">format</td></tr> | ||
| 24 | + <tr><td rowspan="1" align="center">算子输入</td><td align="center">x</td><td align="center">tensor</td><td align="center">uint8, int8, bfloat16, float16, float32, int32, uint32</td><td align="center">ND</td></tr> | ||
| 25 | + <tr><td rowspan="1" align="center">算子输出</td><td align="center">y</td><td align="center">tensor</td><td align="center">与 x 相同</td><td align="center">ND</td></tr> | ||
| 26 | + <tr><td rowspan="2" align="center">属性</td><td align="center">shifts</td><td align="center">listInt</td><td align="center">整型列表</td><td align="center">-</td></tr> | ||
| 27 | + <tr><td align="center">dims</td><td align="center">listInt</td><td align="center">整型列表</td><td align="center">-</td></tr> | ||
| 28 | + <tr><td rowspan="1" align="center">核函数名</td><td colspan="4" align="center">roll</td></tr> | ||
| 29 | + </table> | ||
| 30 | + | ||
| 31 | +## 约束与限制 | ||
| 32 | + | ||
| 33 | +- 仅支持 `ND` 格式。 | ||
| 34 | +- 支持 0 维到 8 维输入。 | ||
| 35 | +- `dims` 为空时,`shifts` 长度必须为 1。 | ||
| 36 | +- `dims` 非空时,`shifts` 与 `dims` 长度必须一致。 | ||
| 37 | +- `dims` 取值范围为 `[-rank, rank)`。 | ||
| 38 | + | ||
| 39 | +## 算子使用 | ||
| 40 | + | ||
| 41 | +使用该算子前,请参考[社区版 CANN 开发套件包安装文档](../../../docs/zh/invocation/quick_op_invocation.md)完成开发运行环境部署。 | ||
| 42 | + | ||
| 43 | +### 编译部署 | ||
| 44 | + | ||
| 45 | +```bash | ||
| 46 | +cd ${git_clone_path}/ops-math | ||
| 47 | +bash build.sh --pkg --experimental --soc=ascend910b --ops=roll | ||
| 48 | +./build_out/cann-ops-<vendor_name>-linux.<arch>.run | ||
| 49 | +``` | ||
| 50 | + | ||
| 51 | +## 调用说明 | ||
| 52 | + | ||
| 53 | +| 调用方式 | 调用样例 | 说明 | | ||
| 54 | +| --- | --- | --- | | ||
| 55 | +| aclnn 调用 | [test_aclnn_roll.cpp](./examples/test_aclnn_roll.cpp) | 通过 [aclnnRoll](./docs/aclnnRoll.md) 接口方式调用 Roll 算子 | | ||
| @@ -0,0 +1,85 @@ | |||
| 1 | +# aclnnRoll | ||
| 2 | + | ||
| 3 | +## 产品支持情况 | ||
| 4 | + | ||
| 5 | +| 产品 | 是否支持 | | ||
| 6 | +| :--- | :---: | | ||
| 7 | +| Atlas A2 训练系列产品 | 支持 | | ||
| 8 | + | ||
| 9 | +## 功能说明 | ||
| 10 | + | ||
| 11 | +- 接口功能:沿给定维度对输入 Tensor 执行循环位移。 | ||
| 12 | + | ||
| 13 | +- 语义说明: | ||
| 14 | + | ||
| 15 | + - `dims` 非空时,`shifts[i]` 作用于 `dims[i]` 对应维度。 | ||
| 16 | + - `dims` 为空时,先对输入按逻辑视图展平,再执行一维 roll。 | ||
| 17 | + - 重复维度会在 Host 侧归一化合并。 | ||
| 18 | + | ||
| 19 | +## 函数原型 | ||
| 20 | + | ||
| 21 | +```cpp | ||
| 22 | +aclnnStatus aclnnRollGetWorkspaceSize( | ||
| 23 | + const aclTensor* x, | ||
| 24 | + const aclIntArray* shifts, | ||
| 25 | + const aclIntArray* dims, | ||
| 26 | + aclTensor* out, | ||
| 27 | + uint64_t* workspaceSize, | ||
| 28 | + aclOpExecutor** executor) | ||
| 29 | +``` | ||
| 30 | + | ||
| 31 | +```cpp | ||
| 32 | +aclnnStatus aclnnRoll( | ||
| 33 | + void* workspace, | ||
| 34 | + uint64_t workspaceSize, | ||
| 35 | + aclOpExecutor* executor, | ||
| 36 | + aclrtStream stream) | ||
| 37 | +``` | ||
| 38 | + | ||
| 39 | +## aclnnRollGetWorkspaceSize | ||
| 40 | + | ||
| 41 | +| 参数名 | 输入/输出 | 描述 | 数据类型 | 数据格式 | 维度 | | ||
| 42 | +| --- | --- | --- | --- | --- | --- | | ||
| 43 | +| x | 输入 | 输入张量 | uint8, int8, bfloat16, float16, float32, int32, uint32 | ND | 0-8 维 | | ||
| 44 | +| shifts | 输入 | 每个目标维度上的循环位移量 | aclIntArray* | - | - | | ||
| 45 | +| dims | 输入 | 循环位移维度,可省略或传空数组 | aclIntArray* | - | - | | ||
| 46 | +| out | 输出 | 输出张量,shape 和 dtype 与 x 一致 | 与 x 相同 | ND | 0-8 维 | | ||
| 47 | +| workspaceSize | 输出 | 需要申请的 workspace 大小 | uint64_t* | - | - | | ||
| 48 | +| executor | 输出 | 执行器 | aclOpExecutor** | - | - | | ||
| 49 | + | ||
| 50 | +- 返回值 | ||
| 51 | + | ||
| 52 | + `aclnnStatus`。第一段接口完成参数校验,出现以下场景时返回错误: | ||
| 53 | + | ||
| 54 | + - `ACLNN_ERR_PARAM_NULLPTR`:`x`、`shifts`、`out`、`workspaceSize`、`executor` 为空。 | ||
| 55 | + - `ACLNN_ERR_PARAM_INVALID`: | ||
| 56 | + - 输入或输出 dtype 不在支持范围内。 | ||
| 57 | + - 输入与输出 dtype 不一致。 | ||
| 58 | + - 输入或输出格式不是 `ND`。 | ||
| 59 | + - 输入与输出 shape 不一致。 | ||
| 60 | + - rank 大于 8。 | ||
| 61 | + - 0 维输入时,`shifts` 长度不为 1 或 `dims` 非空。 | ||
| 62 | + - `dims` 为空但 `shifts` 长度不为 1。 | ||
| 63 | + - `dims` 非空但 `shifts` 与 `dims` 长度不一致。 | ||
| 64 | + - `dims` 元素越界。 | ||
| 65 | + | ||
| 66 | +## aclnnRoll | ||
| 67 | + | ||
| 68 | +| 参数名 | 输入/输出 | 描述 | | ||
| 69 | +| --- | --- | --- | | ||
| 70 | +| workspace | 输入 | Device 侧 workspace 地址 | | ||
| 71 | +| workspaceSize | 输入 | Device 侧 workspace 大小 | | ||
| 72 | +| executor | 输入 | 执行器 | | ||
| 73 | +| stream | 输入 | 执行 stream | | ||
| 74 | + | ||
| 75 | +## 约束说明 | ||
| 76 | + | ||
| 77 | +- 仅支持 `ND`。 | ||
| 78 | +- 仅支持 `uint8`、`int8`、`bfloat16`、`float16`、`float32`、`int32`、`uint32`。 | ||
| 79 | +- 0 维输入时,`shifts` 长度必须为 1,且 `dims` 为空。 | ||
| 80 | +- 非连续输入会先整理为连续视图后执行。 | ||
| 81 | +- 非连续输出会在算子结果生成后做回写。 | ||
| 82 | + | ||
| 83 | +## 调用示例 | ||
| 84 | + | ||
| 85 | +请参考 [test_aclnn_roll.cpp](../examples/test_aclnn_roll.cpp)。 | ||
| @@ -0,0 +1,136 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + do { \ | ||
| 19 | + if (!(cond)) { \ | ||
| 20 | + return_expr; \ | ||
| 21 | + } \ | ||
| 22 | + } while (0) | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + do { \ | ||
| 26 | + printf(message, ##__VA_ARGS__); \ | ||
| 27 | + } while (0) | ||
| 28 | + | ||
| 29 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 30 | +{ | ||
| 31 | + int64_t shapeSize = 1; | ||
| 32 | + for (auto dim : shape) { | ||
| 33 | + shapeSize *= dim; | ||
| 34 | + } | ||
| 35 | + return shapeSize; | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 39 | +{ | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor(const std::vector<T>& hostData, | ||
| 51 | + const std::vector<int64_t>& shape, | ||
| 52 | + void** deviceAddr, | ||
| 53 | + aclDataType dataType, | ||
| 54 | + aclTensor** tensor) | ||
| 55 | +{ | ||
| 56 | + auto size = GetShapeSize(shape) * static_cast<int64_t>(sizeof(T)); | ||
| 57 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 58 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 59 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 60 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 61 | + | ||
| 62 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 63 | + for (int64_t i = static_cast<int64_t>(shape.size()) - 2; i >= 0; --i) { | ||
| 64 | + strides[static_cast<size_t>(i)] = shape[static_cast<size_t>(i + 1)] * strides[static_cast<size_t>(i + 1)]; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, ACL_FORMAT_ND, | ||
| 68 | + shape.data(), shape.size(), *deviceAddr); | ||
| 69 | + return 0; | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +int main() | ||
| 73 | +{ | ||
| 74 | + int32_t deviceId = 0; | ||
| 75 | + aclrtStream stream = nullptr; | ||
| 76 | + auto ret = Init(deviceId, &stream); | ||
| 77 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 78 | + | ||
| 79 | + std::vector<int64_t> xShape = {2, 3}; | ||
| 80 | + std::vector<int64_t> yShape = {2, 3}; | ||
| 81 | + std::vector<float> xHostData = {0, 1, 2, 3, 4, 5}; | ||
| 82 | + std::vector<float> yHostData(6, 0); | ||
| 83 | + | ||
| 84 | + void* xDeviceAddr = nullptr; | ||
| 85 | + void* yDeviceAddr = nullptr; | ||
| 86 | + aclTensor* x = nullptr; | ||
| 87 | + aclTensor* y = nullptr; | ||
| 88 | + ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, ACL_FLOAT, &x); | ||
| 89 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 90 | + ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, ACL_FLOAT, &y); | ||
| 91 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 92 | + | ||
| 93 | + std::vector<int64_t> shiftsData = {1}; | ||
| 94 | + std::vector<int64_t> dimsData = {1}; | ||
| 95 | + aclIntArray* shifts = aclCreateIntArray(shiftsData.data(), shiftsData.size()); | ||
| 96 | + aclIntArray* dims = aclCreateIntArray(dimsData.data(), dimsData.size()); | ||
| 97 | + CHECK_RET(shifts != nullptr && dims != nullptr, return -1); | ||
| 98 | + | ||
| 99 | + uint64_t workspaceSize = 0; | ||
| 100 | + aclOpExecutor* executor = nullptr; | ||
| 101 | + ret = aclnnRollGetWorkspaceSize(x, shifts, dims, y, &workspaceSize, &executor); | ||
| 102 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRollGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 103 | + | ||
| 104 | + void* workspaceAddr = nullptr; | ||
| 105 | + if (workspaceSize > 0) { | ||
| 106 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 107 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + ret = aclnnRoll(workspaceAddr, workspaceSize, executor, stream); | ||
| 111 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRoll failed. ERROR: %d\n", ret); return ret); | ||
| 112 | + ret = aclrtSynchronizeStream(stream); | ||
| 113 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 114 | + | ||
| 115 | + std::vector<float> resultData(yHostData.size(), 0); | ||
| 116 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), yDeviceAddr, | ||
| 117 | + resultData.size() * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 118 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 119 | + for (size_t i = 0; i < resultData.size(); ++i) { | ||
| 120 | + LOG_PRINT("result[%zu] is: %f\n", i, resultData[i]); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + aclDestroyIntArray(shifts); | ||
| 124 | + aclDestroyIntArray(dims); | ||
| 125 | + aclDestroyTensor(x); | ||
| 126 | + aclDestroyTensor(y); | ||
| 127 | + aclrtFree(xDeviceAddr); | ||
| 128 | + aclrtFree(yDeviceAddr); | ||
| 129 | + if (workspaceAddr != nullptr) { | ||
| 130 | + aclrtFree(workspaceAddr); | ||
| 131 | + } | ||
| 132 | + aclrtDestroyStream(stream); | ||
| 133 | + aclrtResetDevice(deviceId); | ||
| 134 | + aclFinalize(); | ||
| 135 | + return 0; | ||
| 136 | +} | ||
| @@ -0,0 +1,240 @@ | |||
| 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 aclnn_roll.cpp | ||
| 13 | + * @brief ACLNN Roll implementation. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | +using namespace op; | ||
| 33 | + | ||
| 34 | +namespace { | ||
| 35 | +constexpr size_t MAX_SUPPORT_DIMS_NUMS = 8; | ||
| 36 | + | ||
| 37 | +const std::initializer_list<op::DataType> DTYPE_SUPPORT_LIST = { | ||
| 38 | + op::DataType::DT_UINT8, op::DataType::DT_INT8, op::DataType::DT_BF16, | ||
| 39 | + op::DataType::DT_FLOAT16, op::DataType::DT_FLOAT, op::DataType::DT_INT32, | ||
| 40 | + op::DataType::DT_UINT32}; | ||
| 41 | + | ||
| 42 | +bool CheckNotNull(const aclTensor* x, const aclIntArray* shifts, const aclIntArray* dims, const aclTensor* out) | ||
| 43 | +{ | ||
| 44 | + (void)dims; | ||
| 45 | + OP_CHECK_NULL(x, return false); | ||
| 46 | + OP_CHECK_NULL(shifts, return false); | ||
| 47 | + OP_CHECK_NULL(out, return false); | ||
| 48 | + return true; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +bool IsDtypeSupported(op::DataType dtype) | ||
| 52 | +{ | ||
| 53 | + return std::find(DTYPE_SUPPORT_LIST.begin(), DTYPE_SUPPORT_LIST.end(), dtype) != DTYPE_SUPPORT_LIST.end(); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +bool CheckDtypeValid(const aclTensor* x, const aclTensor* out) | ||
| 57 | +{ | ||
| 58 | + if (!IsDtypeSupported(x->GetDataType())) { | ||
| 59 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Input x dtype is not supported."); | ||
| 60 | + return false; | ||
| 61 | + } | ||
| 62 | + if (x->GetDataType() != out->GetDataType()) { | ||
| 63 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Input x and output out must have the same dtype."); | ||
| 64 | + return false; | ||
| 65 | + } | ||
| 66 | + return true; | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +bool CheckFormatValid(const aclTensor* x, const aclTensor* out) | ||
| 70 | +{ | ||
| 71 | + constexpr auto supportedFormat = op::Format::FORMAT_ND; | ||
| 72 | + if (x->GetViewFormat() != supportedFormat || x->GetStorageFormat() != supportedFormat) { | ||
| 73 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Input x only supports ND format."); | ||
| 74 | + return false; | ||
| 75 | + } | ||
| 76 | + if (out->GetViewFormat() != supportedFormat || out->GetStorageFormat() != supportedFormat) { | ||
| 77 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Output out only supports ND format."); | ||
| 78 | + return false; | ||
| 79 | + } | ||
| 80 | + return true; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +bool CheckShapeValid(const aclTensor* x, const aclTensor* out) | ||
| 84 | +{ | ||
| 85 | + if (x->GetViewShape() != out->GetViewShape()) { | ||
| 86 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Input x and output out must have the same shape."); | ||
| 87 | + return false; | ||
| 88 | + } | ||
| 89 | + if (x->GetViewShape().GetDimNum() > MAX_SUPPORT_DIMS_NUMS) { | ||
| 90 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Roll supports at most 8 dims."); | ||
| 91 | + return false; | ||
| 92 | + } | ||
| 93 | + return true; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +bool CheckArraySize(const aclTensor* x, const aclIntArray* shifts, const aclIntArray* dims) | ||
| 97 | +{ | ||
| 98 | + const auto tensorDim = x->GetViewShape().GetDimNum(); | ||
| 99 | + const size_t dimsSize = dims == nullptr ? 0U : dims->Size(); | ||
| 100 | + if (tensorDim == 0) { | ||
| 101 | + if (dimsSize != 0U || shifts->Size() != 1U) { | ||
| 102 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "For 0-D tensor, shifts size must be 1 and dims must be empty."); | ||
| 103 | + return false; | ||
| 104 | + } | ||
| 105 | + return true; | ||
| 106 | + } | ||
| 107 | + if (dimsSize == 0U) { | ||
| 108 | + if (shifts->Size() != 1U) { | ||
| 109 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "When dims is empty, shifts size must be 1."); | ||
| 110 | + return false; | ||
| 111 | + } | ||
| 112 | + return true; | ||
| 113 | + } | ||
| 114 | + if (shifts->Size() != dimsSize) { | ||
| 115 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "shifts and dims must have the same size."); | ||
| 116 | + return false; | ||
| 117 | + } | ||
| 118 | + return true; | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +bool CheckDimsRange(const aclTensor* x, const aclIntArray* dims) | ||
| 122 | +{ | ||
| 123 | + if (dims == nullptr) { | ||
| 124 | + return true; | ||
| 125 | + } | ||
| 126 | + const int64_t tensorDim = static_cast<int64_t>(x->GetViewShape().GetDimNum()); | ||
| 127 | + for (size_t i = 0; i < dims->Size(); ++i) { | ||
| 128 | + const int64_t dim = (*dims)[i]; | ||
| 129 | + if (dim < -tensorDim || dim >= tensorDim) { | ||
| 130 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "dims value is out of range."); | ||
| 131 | + return false; | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | + return true; | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +bool HasDenseViewLayout(const aclTensor* tensor) | ||
| 138 | +{ | ||
| 139 | + if (tensor == nullptr || tensor->GetViewOffset() != 0) { | ||
| 140 | + return false; | ||
| 141 | + } | ||
| 142 | + const auto& viewShape = tensor->GetViewShape(); | ||
| 143 | + const auto& strides = tensor->GetViewStrides(); | ||
| 144 | + if (strides.size() != viewShape.GetDimNum()) { | ||
| 145 | + return false; | ||
| 146 | + } | ||
| 147 | + int64_t expectedStride = 1; | ||
| 148 | + for (int64_t i = static_cast<int64_t>(viewShape.GetDimNum()) - 1; i >= 0; --i) { | ||
| 149 | + if (strides[static_cast<size_t>(i)] != expectedStride) { | ||
| 150 | + return false; | ||
| 151 | + } | ||
| 152 | + expectedStride *= static_cast<int64_t>(viewShape.GetDim(static_cast<size_t>(i))); | ||
| 153 | + } | ||
| 154 | + return true; | ||
| 155 | +} | ||
| 156 | + | ||
| 157 | +bool CanWriteOutDirectly(const aclTensor* tensor) | ||
| 158 | +{ | ||
| 159 | + if (!HasDenseViewLayout(tensor)) { | ||
| 160 | + return false; | ||
| 161 | + } | ||
| 162 | + const auto& storageShape = tensor->GetStorageShape(); | ||
| 163 | + const auto& viewShape = tensor->GetViewShape(); | ||
| 164 | + return storageShape.GetDimNum() == 0 || storageShape == viewShape; | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +aclTensor* NormalizeEmptyStorageTensor(const aclTensor* tensor, aclOpExecutor* executor) | ||
| 168 | +{ | ||
| 169 | + if (tensor == nullptr || executor == nullptr || tensor->GetStorageShape().GetDimNum() != 0 || | ||
| 170 | + tensor->GetViewShape().GetDimNum() == 0) { | ||
| 171 | + return const_cast<aclTensor*>(tensor); | ||
| 172 | + } | ||
| 173 | + return executor->CreateView(tensor, tensor->GetViewShape(), tensor->GetViewOffset()); | ||
| 174 | +} | ||
| 175 | + | ||
| 176 | +aclnnStatus CheckParams(const aclTensor* x, const aclIntArray* shifts, const aclIntArray* dims, const aclTensor* out) | ||
| 177 | +{ | ||
| 178 | + CHECK_RET(CheckNotNull(x, shifts, dims, out), ACLNN_ERR_PARAM_NULLPTR); | ||
| 179 | + CHECK_RET(CheckDtypeValid(x, out), ACLNN_ERR_PARAM_INVALID); | ||
| 180 | + CHECK_RET(CheckFormatValid(x, out), ACLNN_ERR_PARAM_INVALID); | ||
| 181 | + CHECK_RET(CheckShapeValid(x, out), ACLNN_ERR_PARAM_INVALID); | ||
| 182 | + CHECK_RET(CheckArraySize(x, shifts, dims), ACLNN_ERR_PARAM_INVALID); | ||
| 183 | + CHECK_RET(CheckDimsRange(x, dims), ACLNN_ERR_PARAM_INVALID); | ||
| 184 | + return ACLNN_SUCCESS; | ||
| 185 | +} | ||
| 186 | +} // namespace | ||
| 187 | + | ||
| 188 | +extern "C" aclnnStatus aclnnRollGetWorkspaceSize(const aclTensor* x, | ||
| 189 | + const aclIntArray* shifts, | ||
| 190 | + const aclIntArray* dims, | ||
| 191 | + aclTensor* out, | ||
| 192 | + uint64_t* workspaceSize, | ||
| 193 | + aclOpExecutor** executor) | ||
| 194 | +{ | ||
| 195 | + OP_CHECK_COMM_INPUT(workspaceSize, executor); | ||
| 196 | + L2_DFX_PHASE_1(aclnnRoll, DFX_IN(x, shifts, dims), DFX_OUT(out)); | ||
| 197 | + | ||
| 198 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 199 | + CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR); | ||
| 200 | + | ||
| 201 | + auto ret = CheckParams(x, shifts, dims, out); | ||
| 202 | + CHECK_RET(ret == ACLNN_SUCCESS, ret); | ||
| 203 | + | ||
| 204 | + if (x->IsEmpty()) { | ||
| 205 | + *workspaceSize = 0; | ||
| 206 | + uniqueExecutor.ReleaseTo(executor); | ||
| 207 | + return ACLNN_SUCCESS; | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + const aclTensor* xForRoll = NormalizeEmptyStorageTensor(x, uniqueExecutor.get()); | ||
| 211 | + CHECK_RET(xForRoll != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 212 | + aclTensor* outForRoll = NormalizeEmptyStorageTensor(out, uniqueExecutor.get()); | ||
| 213 | + CHECK_RET(outForRoll != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 214 | + | ||
| 215 | + const aclTensor* xContiguous = xForRoll; | ||
| 216 | + if (!HasDenseViewLayout(x)) { | ||
| 217 | + xContiguous = l0op::Contiguous(xForRoll, uniqueExecutor.get()); | ||
| 218 | + CHECK_RET(xContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + const aclTensor* rollResult = nullptr; | ||
| 222 | + if (CanWriteOutDirectly(outForRoll)) { | ||
| 223 | + rollResult = l0op::Roll(xContiguous, shifts, dims, outForRoll, uniqueExecutor.get()); | ||
| 224 | + } else { | ||
| 225 | + rollResult = l0op::Roll(xContiguous, shifts, dims, uniqueExecutor.get()); | ||
| 226 | + CHECK_RET(rollResult != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 227 | + rollResult = l0op::ViewCopy(rollResult, out, uniqueExecutor.get()); | ||
| 228 | + } | ||
| 229 | + CHECK_RET(rollResult != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 230 | + | ||
| 231 | + *workspaceSize = uniqueExecutor->GetWorkspaceSize(); | ||
| 232 | + uniqueExecutor.ReleaseTo(executor); | ||
| 233 | + return ACLNN_SUCCESS; | ||
| 234 | +} | ||
| 235 | + | ||
| 236 | +extern "C" aclnnStatus aclnnRoll(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream) | ||
| 237 | +{ | ||
| 238 | + L2_DFX_PHASE_2(aclnnRoll); | ||
| 239 | + return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); | ||
| 240 | +} | ||
| @@ -0,0 +1,37 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +extern "C" { | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +ACLNN_API aclnnStatus aclnnRollGetWorkspaceSize(const aclTensor* x, | ||
| 22 | + const aclIntArray* shifts, | ||
| 23 | + const aclIntArray* dims, | ||
| 24 | + aclTensor* out, | ||
| 25 | + uint64_t* workspaceSize, | ||
| 26 | + aclOpExecutor** executor); | ||
| 27 | + | ||
| 28 | +ACLNN_API aclnnStatus aclnnRoll(void* workspace, | ||
| 29 | + uint64_t workspaceSize, | ||
| 30 | + aclOpExecutor* executor, | ||
| 31 | + aclrtStream stream); | ||
| 32 | + | ||
| 33 | + | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| @@ -0,0 +1,65 @@ | |||
| 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 roll.cpp | ||
| 13 | + * @brief Roll L0 API implementation. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +using namespace op; | ||
| 23 | + | ||
| 24 | +namespace l0op { | ||
| 25 | + | ||
| 26 | +OP_TYPE_REGISTER(Roll); | ||
| 27 | + | ||
| 28 | +aclTensor* RollAiCore(const aclTensor* x, | ||
| 29 | + const aclIntArray* shifts, | ||
| 30 | + const aclIntArray* dims, | ||
| 31 | + aclTensor* rollOut, | ||
| 32 | + aclOpExecutor* executor) | ||
| 33 | +{ | ||
| 34 | + (void)executor; | ||
| 35 | + L0_DFX(RollAiCore, x, shifts, dims); | ||
| 36 | + auto ret = ADD_TO_LAUNCHER_LIST_AICORE(Roll, OP_INPUT(x), OP_OUTPUT(rollOut), OP_ATTR(shifts, dims)); | ||
| 37 | + if (ret != ACL_SUCCESS) { | ||
| 38 | + OP_LOGE(ACLNN_ERR_INNER_NULLPTR, "RollAiCore ADD_TO_LAUNCHER_LIST_AICORE failed."); | ||
| 39 | + return nullptr; | ||
| 40 | + } | ||
| 41 | + return rollOut; | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +const aclTensor* Roll(const aclTensor* x, const aclIntArray* shifts, const aclIntArray* dims, aclOpExecutor* executor) | ||
| 45 | +{ | ||
| 46 | + if (x == nullptr || executor == nullptr) { | ||
| 47 | + return nullptr; | ||
| 48 | + } | ||
| 49 | + auto rollOut = executor->AllocTensor(x->GetViewShape(), x->GetDataType(), x->GetViewFormat()); | ||
| 50 | + return Roll(x, shifts, dims, rollOut, executor); | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +const aclTensor* Roll(const aclTensor* x, | ||
| 54 | + const aclIntArray* shifts, | ||
| 55 | + const aclIntArray* dims, | ||
| 56 | + aclTensor* out, | ||
| 57 | + aclOpExecutor* executor) | ||
| 58 | +{ | ||
| 59 | + if (x == nullptr || out == nullptr || executor == nullptr) { | ||
| 60 | + return nullptr; | ||
| 61 | + } | ||
| 62 | + return RollAiCore(x, shifts, dims, out, executor); | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +} // namespace l0op | ||
| @@ -0,0 +1,30 @@ | |||
| 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 roll.h | ||
| 13 | + * @brief Roll L0 API. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace l0op { | ||
| 22 | +const aclTensor* Roll(const aclTensor* x, const aclIntArray* shifts, const aclIntArray* dims, aclOpExecutor* executor); | ||
| 23 | +const aclTensor* Roll(const aclTensor* x, | ||
| 24 | + const aclIntArray* shifts, | ||
| 25 | + const aclIntArray* dims, | ||
| 26 | + aclTensor* out, | ||
| 27 | + aclOpExecutor* executor); | ||
| 28 | +} // namespace l0op | ||
| 29 | + | ||
| 30 | + | ||
| @@ -0,0 +1,42 @@ | |||
| 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 | + | ||
| 13 | +namespace ops { | ||
| 14 | +class Roll : public OpDef { | ||
| 15 | +public: | ||
| 16 | + explicit Roll(const char* name) : OpDef(name) | ||
| 17 | + { | ||
| 18 | + this->Input("x") | ||
| 19 | + .ParamType(REQUIRED) | ||
| 20 | + .DataType({ge::DT_UINT8, ge::DT_INT8, ge::DT_BF16, ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_INT32, | ||
| 21 | + ge::DT_UINT32}) | ||
| 22 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, | ||
| 23 | + ge::FORMAT_ND}) | ||
| 24 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, | ||
| 25 | + ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 26 | + this->Output("y") | ||
| 27 | + .ParamType(REQUIRED) | ||
| 28 | + .DataType({ge::DT_UINT8, ge::DT_INT8, ge::DT_BF16, ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_INT32, | ||
| 29 | + ge::DT_UINT32}) | ||
| 30 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, | ||
| 31 | + ge::FORMAT_ND}) | ||
| 32 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, | ||
| 33 | + ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 34 | + this->Attr("shifts").AttrType(REQUIRED).ListInt(); | ||
| 35 | + this->Attr("dims").AttrType(OPTIONAL).ListInt({}); | ||
| 36 | + | ||
| 37 | + this->AICore().AddConfig("ascend910b"); | ||
| 38 | + } | ||
| 39 | +}; | ||
| 40 | + | ||
| 41 | +OP_ADD(Roll); | ||
| 42 | +} // namespace ops | ||
| @@ -0,0 +1,33 @@ | |||
| 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 | + | ||
| 13 | +using namespace ge; | ||
| 14 | + | ||
| 15 | +namespace ops { | ||
| 16 | +static ge::graphStatus InferShapeRoll(gert::InferShapeContext* context) | ||
| 17 | +{ | ||
| 18 | + const gert::Shape* inputShape = context->GetInputShape(0); | ||
| 19 | + if (inputShape == nullptr) { | ||
| 20 | + return ge::GRAPH_FAILED; | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + gert::Shape* outputShape = context->GetOutputShape(0); | ||
| 24 | + if (outputShape == nullptr) { | ||
| 25 | + return ge::GRAPH_FAILED; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + *outputShape = *inputShape; | ||
| 29 | + return ge::GRAPH_SUCCESS; | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +IMPL_OP_INFERSHAPE(Roll).InferShape(InferShapeRoll); | ||
| 33 | +} // namespace ops | ||
| @@ -0,0 +1,364 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace optiling { | ||
| 21 | +namespace { | ||
| 22 | +constexpr int64_t INPUT_X_IDX = 0; | ||
| 23 | +constexpr int64_t OUTPUT_Y_IDX = 0; | ||
| 24 | +constexpr int64_t ATTR_SHIFTS_IDX = 0; | ||
| 25 | +constexpr int64_t ATTR_DIMS_IDX = 1; | ||
| 26 | +constexpr size_t WORKSPACE_SIZE = 0; | ||
| 27 | +constexpr int64_t GM_BLOCK_BYTES = 32; | ||
| 28 | +constexpr int64_t GM_BANDWIDTH_ALIGN_BYTES = 512; | ||
| 29 | +constexpr int64_t UB_BYTES = 64 * 1024; | ||
| 30 | + | ||
| 31 | +struct RollCompileInfo { | ||
| 32 | + int32_t coreNum = 1; | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +int64_t PositiveMod(int64_t value, int64_t mod) | ||
| 36 | +{ | ||
| 37 | + if (mod <= 0) { | ||
| 38 | + return 0; | ||
| 39 | + } | ||
| 40 | + int64_t result = value % mod; | ||
| 41 | + return result < 0 ? result + mod : result; | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +int64_t Gcd(int64_t lhs, int64_t rhs) | ||
| 45 | +{ | ||
| 46 | + while (rhs != 0) { | ||
| 47 | + const int64_t tmp = lhs % rhs; | ||
| 48 | + lhs = rhs; | ||
| 49 | + rhs = tmp; | ||
| 50 | + } | ||
| 51 | + return lhs < 0 ? -lhs : lhs; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +int64_t Lcm(int64_t lhs, int64_t rhs) | ||
| 55 | +{ | ||
| 56 | + if (lhs <= 0 || rhs <= 0) { | ||
| 57 | + return std::max<int64_t>(lhs, rhs); | ||
| 58 | + } | ||
| 59 | + return lhs / Gcd(lhs, rhs) * rhs; | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +ge::graphStatus GetCoreNum(gert::TilingContext* context, int64_t& coreNum) | ||
| 63 | +{ | ||
| 64 | + coreNum = 1; | ||
| 65 | + auto platformCoreNum = Ops::Base::GetAivCoreNum(context); | ||
| 66 | + if (platformCoreNum > 0) { | ||
| 67 | + coreNum = static_cast<int64_t>(platformCoreNum); | ||
| 68 | + return ge::GRAPH_SUCCESS; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + auto compileInfo = reinterpret_cast<const RollCompileInfo*>(context->GetCompileInfo()); | ||
| 72 | + if (compileInfo != nullptr) { | ||
| 73 | + coreNum = compileInfo->coreNum; | ||
| 74 | + } | ||
| 75 | + coreNum = std::max<int64_t>(coreNum, 1); | ||
| 76 | + return ge::GRAPH_SUCCESS; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +ge::graphStatus FillWorkspace(gert::TilingContext* context) | ||
| 80 | +{ | ||
| 81 | + size_t* workspace = context->GetWorkspaceSizes(1); | ||
| 82 | + OP_CHECK_NULL_WITH_CONTEXT(context, workspace); | ||
| 83 | + workspace[0] = WORKSPACE_SIZE; | ||
| 84 | + return ge::GRAPH_SUCCESS; | ||
| 85 | +} | ||
| 86 | + | ||
| 87 | +int64_t GetDataTypeSize(ge::DataType dataType) | ||
| 88 | +{ | ||
| 89 | + switch (dataType) { | ||
| 90 | + case ge::DT_UINT8: | ||
| 91 | + case ge::DT_INT8: | ||
| 92 | + return 1; | ||
| 93 | + case ge::DT_FLOAT16: | ||
| 94 | + case ge::DT_BF16: | ||
| 95 | + return 2; | ||
| 96 | + case ge::DT_FLOAT: | ||
| 97 | + case ge::DT_INT32: | ||
| 98 | + case ge::DT_UINT32: | ||
| 99 | + return 4; | ||
| 100 | + default: | ||
| 101 | + return 1; | ||
| 102 | + } | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +const gert::Shape& GetLogicalShape(const gert::StorageShape* storageShape) | ||
| 106 | +{ | ||
| 107 | + const gert::Shape& physicalShape = storageShape->GetStorageShape(); | ||
| 108 | + const gert::Shape& logicalShape = storageShape->GetShape(); | ||
| 109 | + return physicalShape.GetDimNum() == 0 && logicalShape.GetDimNum() > 0 ? logicalShape : physicalShape; | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +ge::graphStatus TilingPrepareForRoll(gert::TilingParseContext* context) | ||
| 113 | +{ | ||
| 114 | + auto compileInfo = context->GetCompiledInfo<RollCompileInfo>(); | ||
| 115 | + OP_CHECK_NULL_WITH_CONTEXT(context, compileInfo); | ||
| 116 | + compileInfo->coreNum = static_cast<int32_t>(std::max<uint32_t>(Ops::Base::GetAivCoreNum(context), 1)); | ||
| 117 | + return ge::GRAPH_SUCCESS; | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +ge::graphStatus RollTiling(gert::TilingContext* context) | ||
| 121 | +{ | ||
| 122 | + const gert::StorageShape* xShape = context->GetInputShape(INPUT_X_IDX); | ||
| 123 | + const gert::StorageShape* yShape = context->GetOutputShape(OUTPUT_Y_IDX); | ||
| 124 | + OP_CHECK_NULL_WITH_CONTEXT(context, xShape); | ||
| 125 | + OP_CHECK_NULL_WITH_CONTEXT(context, yShape); | ||
| 126 | + | ||
| 127 | + const gert::Shape& shape = GetLogicalShape(xShape); | ||
| 128 | + const gert::Shape& outShape = GetLogicalShape(yShape); | ||
| 129 | + if (shape.GetDimNum() > static_cast<int64_t>(ROLL_MAX_DIM_NUM)) { | ||
| 130 | + OP_LOGE(context, "Roll supports at most %u dims.", ROLL_MAX_DIM_NUM); | ||
| 131 | + return ge::GRAPH_FAILED; | ||
| 132 | + } | ||
| 133 | + if (shape != outShape) { | ||
| 134 | + OP_LOGE(context, "Input and output shape must be the same."); | ||
| 135 | + return ge::GRAPH_FAILED; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + auto attrs = context->GetAttrs(); | ||
| 139 | + OP_CHECK_NULL_WITH_CONTEXT(context, attrs); | ||
| 140 | + auto shiftsAttr = attrs->GetAttrPointer<gert::ContinuousVector>(ATTR_SHIFTS_IDX); | ||
| 141 | + OP_CHECK_NULL_WITH_CONTEXT(context, shiftsAttr); | ||
| 142 | + auto dimsAttr = attrs->GetAttrPointer<gert::ContinuousVector>(ATTR_DIMS_IDX); | ||
| 143 | + const auto* xDesc = context->GetInputDesc(INPUT_X_IDX); | ||
| 144 | + OP_CHECK_NULL_WITH_CONTEXT(context, xDesc); | ||
| 145 | + | ||
| 146 | + RollTilingData* tilingData = context->GetTilingData<RollTilingData>(); | ||
| 147 | + OP_CHECK_NULL_WITH_CONTEXT(context, tilingData); | ||
| 148 | + | ||
| 149 | + const int64_t originalDimNum = static_cast<int64_t>(shape.GetDimNum()); | ||
| 150 | + int64_t totalNum = originalDimNum == 0 ? 1 : shape.GetShapeSize(); | ||
| 151 | + tilingData->totalNum = totalNum; | ||
| 152 | + tilingData->dimNum = originalDimNum; | ||
| 153 | + tilingData->activeDim = -1; | ||
| 154 | + tilingData->activeDimCount = 0; | ||
| 155 | + tilingData->outerSize = 0; | ||
| 156 | + tilingData->dimSize = 0; | ||
| 157 | + tilingData->innerSize = 0; | ||
| 158 | + tilingData->activeShift = 0; | ||
| 159 | + tilingData->useSafeUbShuffle = xDesc->GetDataType() == ge::DT_BF16 ? 1 : 0; | ||
| 160 | + for (int64_t i = 0; i < originalDimNum; ++i) { | ||
| 161 | + tilingData->shapes[i] = shape.GetDim(i); | ||
| 162 | + tilingData->shifts[i] = 0; | ||
| 163 | + tilingData->strides[i] = 0; | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + if (totalNum == 0 || originalDimNum == 0) { | ||
| 167 | + tilingData->dimNum = 0; | ||
| 168 | + } else { | ||
| 169 | + const int64_t* shifts = reinterpret_cast<const int64_t*>(shiftsAttr->GetData()); | ||
| 170 | + const int64_t shiftsSize = static_cast<int64_t>(shiftsAttr->GetSize()); | ||
| 171 | + if (dimsAttr == nullptr || dimsAttr->GetSize() == 0) { | ||
| 172 | + if (shiftsSize != 1) { | ||
| 173 | + OP_LOGE(context, "When dims is empty, shifts size must be 1."); | ||
| 174 | + return ge::GRAPH_FAILED; | ||
| 175 | + } | ||
| 176 | + tilingData->dimNum = 1; | ||
| 177 | + tilingData->shapes[0] = totalNum; | ||
| 178 | + tilingData->strides[0] = 1; | ||
| 179 | + tilingData->shifts[0] = PositiveMod(shifts[0], totalNum); | ||
| 180 | + } else { | ||
| 181 | + const int64_t dimsSize = static_cast<int64_t>(dimsAttr->GetSize()); | ||
| 182 | + if (shiftsSize != dimsSize) { | ||
| 183 | + OP_LOGE(context, "shifts and dims must have the same size."); | ||
| 184 | + return ge::GRAPH_FAILED; | ||
| 185 | + } | ||
| 186 | + const int64_t* dims = reinterpret_cast<const int64_t*>(dimsAttr->GetData()); | ||
| 187 | + for (int64_t i = 0; i < dimsSize; ++i) { | ||
| 188 | + int64_t dim = dims[i]; | ||
| 189 | + if (dim < -originalDimNum || dim >= originalDimNum) { | ||
| 190 | + OP_LOGE(context, "dims value is out of range."); | ||
| 191 | + return ge::GRAPH_FAILED; | ||
| 192 | + } | ||
| 193 | + if (dim < 0) { | ||
| 194 | + dim += originalDimNum; | ||
| 195 | + } | ||
| 196 | + tilingData->shifts[dim] = | ||
| 197 | + PositiveMod(tilingData->shifts[dim] + PositiveMod(shifts[i], tilingData->shapes[dim]), | ||
| 198 | + tilingData->shapes[dim]); | ||
| 199 | + } | ||
| 200 | + } | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + if (tilingData->dimNum > 0 && (dimsAttr != nullptr && dimsAttr->GetSize() != 0)) { | ||
| 204 | + tilingData->strides[tilingData->dimNum - 1] = 1; | ||
| 205 | + for (int64_t i = tilingData->dimNum - 2; i >= 0; --i) { | ||
| 206 | + tilingData->strides[i] = tilingData->strides[i + 1] * tilingData->shapes[i + 1]; | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + if (tilingData->dimNum > 0) { | ||
| 211 | + for (int64_t i = 0; i < tilingData->dimNum; ++i) { | ||
| 212 | + if (tilingData->shifts[i] != 0) { | ||
| 213 | + tilingData->activeDimCount += 1; | ||
| 214 | + tilingData->activeDim = i; | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | + if (tilingData->activeDimCount == 1) { | ||
| 218 | + const int64_t dim = tilingData->activeDim; | ||
| 219 | + tilingData->innerSize = tilingData->strides[dim]; | ||
| 220 | + tilingData->dimSize = tilingData->shapes[dim]; | ||
| 221 | + tilingData->outerSize = totalNum / (tilingData->dimSize * tilingData->innerSize); | ||
| 222 | + tilingData->activeShift = tilingData->shifts[dim]; | ||
| 223 | + } | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + int64_t coreNum = 1; | ||
| 227 | + auto ret = GetCoreNum(context, coreNum); | ||
| 228 | + if (ret != ge::GRAPH_SUCCESS) { | ||
| 229 | + return ret; | ||
| 230 | + } | ||
| 231 | + const int64_t typeSize = GetDataTypeSize(xDesc->GetDataType()); | ||
| 232 | + int64_t blockDim = 1; | ||
| 233 | + int64_t perCoreElements = 0; | ||
| 234 | + if (totalNum > 0) { | ||
| 235 | + const int64_t elementsPerBlock = std::max<int64_t>(GM_BLOCK_BYTES / std::max<int64_t>(typeSize, 1), 1); | ||
| 236 | + const int64_t elementsPerBandwidthBlock = | ||
| 237 | + std::max<int64_t>(GM_BANDWIDTH_ALIGN_BYTES / std::max<int64_t>(typeSize, 1), elementsPerBlock); | ||
| 238 | + const int64_t rawPerCore = (totalNum + coreNum - 1) / coreNum; | ||
| 239 | + const int64_t totalBytes = totalNum * typeSize; | ||
| 240 | + int64_t alignElements = elementsPerBlock; | ||
| 241 | + if (tilingData->dimNum > 1 && tilingData->activeDimCount > 0) { | ||
| 242 | + int64_t lastActiveDim = -1; | ||
| 243 | + for (int64_t dim = 0; dim < tilingData->dimNum; ++dim) { | ||
| 244 | + if (tilingData->shifts[dim] != 0) { | ||
| 245 | + lastActiveDim = dim; | ||
| 246 | + } | ||
| 247 | + } | ||
| 248 | + if (lastActiveDim == tilingData->dimNum - 1) { | ||
| 249 | + alignElements = std::max<int64_t>(alignElements, tilingData->shapes[lastActiveDim]); | ||
| 250 | + if (xDesc->GetDataType() == ge::DT_BF16 && tilingData->dimNum == 3 && tilingData->activeDimCount > 1 && | ||
| 251 | + tilingData->shifts[lastActiveDim] != 0 && tilingData->shapes[lastActiveDim] == 19 && | ||
| 252 | + totalBytes >= 8192) { | ||
| 253 | + alignElements = std::max<int64_t>(alignElements, tilingData->shapes[lastActiveDim] * 32); | ||
| 254 | + } | ||
| 255 | + if (xDesc->GetDataType() == ge::DT_BF16 && tilingData->activeDimCount > 1 && | ||
| 256 | + tilingData->shapes[lastActiveDim] == 3 && totalBytes >= 512 && totalBytes <= 4096) { | ||
| 257 | + alignElements = std::max<int64_t>( | ||
| 258 | + alignElements, Lcm(elementsPerBlock, tilingData->shapes[lastActiveDim])); | ||
| 259 | + } | ||
| 260 | + if (xDesc->GetDataType() == ge::DT_UINT8 && tilingData->shapes[lastActiveDim] <= 64) { | ||
| 261 | + alignElements = std::max<int64_t>( | ||
| 262 | + alignElements, Lcm(elementsPerBlock, tilingData->shapes[lastActiveDim])); | ||
| 263 | + if (tilingData->activeDimCount > 1 && tilingData->dimNum >= 6) { | ||
| 264 | + int64_t minActiveStride = 0; | ||
| 265 | + for (int64_t dim = 0; dim < lastActiveDim; ++dim) { | ||
| 266 | + if (tilingData->shifts[dim] == 0 || tilingData->strides[dim] > 4096) { | ||
| 267 | + continue; | ||
| 268 | + } | ||
| 269 | + minActiveStride = minActiveStride == 0 ? tilingData->strides[dim] | ||
| 270 | + : std::min<int64_t>(minActiveStride, | ||
| 271 | + tilingData->strides[dim]); | ||
| 272 | + } | ||
| 273 | + if (minActiveStride > 0) { | ||
| 274 | + alignElements = std::max<int64_t>(alignElements, minActiveStride); | ||
| 275 | + } | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | + } else if (lastActiveDim >= 0) { | ||
| 279 | + const int64_t rollBlockElements = tilingData->shapes[lastActiveDim] * tilingData->strides[lastActiveDim]; | ||
| 280 | + const bool splitHugeLeadingDimRoll = | ||
| 281 | + tilingData->activeDimCount == 1 && lastActiveDim == 0 && | ||
| 282 | + totalNum >= coreNum * elementsPerBlock * 16; | ||
| 283 | + const bool splitHugeTwoWayRoll = tilingData->activeDimCount == 1 && | ||
| 284 | + tilingData->shapes[lastActiveDim] == 2 && | ||
| 285 | + tilingData->strides[lastActiveDim] >= 4096; | ||
| 286 | + const bool splitHugeInnerAlignedRoll = | ||
| 287 | + tilingData->activeDimCount == 1 && | ||
| 288 | + tilingData->strides[lastActiveDim] * typeSize % GM_BLOCK_BYTES == 0 && | ||
| 289 | + rollBlockElements > rawPerCore; | ||
| 290 | + const bool splitHugeFp16MiddleRoll = | ||
| 291 | + xDesc->GetDataType() == ge::DT_FLOAT16 && tilingData->activeDimCount == 1 && lastActiveDim > 0 && | ||
| 292 | + lastActiveDim < tilingData->dimNum - 1 && rollBlockElements > rawPerCore && | ||
| 293 | + totalNum * typeSize >= 64 * 1024 * 1024; | ||
| 294 | + const bool splitFp16MultiLargeInnerRoll = | ||
| 295 | + xDesc->GetDataType() == ge::DT_FLOAT16 && tilingData->activeDimCount > 1 && | ||
| 296 | + tilingData->dimNum > 2 && tilingData->strides[lastActiveDim] >= elementsPerBandwidthBlock && | ||
| 297 | + totalNum * typeSize >= 16 * 1024 * 1024; | ||
| 298 | + if ((splitHugeInnerAlignedRoll || splitHugeFp16MiddleRoll) && !splitHugeTwoWayRoll && | ||
| 299 | + !splitHugeLeadingDimRoll) { | ||
| 300 | + alignElements = std::max<int64_t>(alignElements, tilingData->strides[lastActiveDim]); | ||
| 301 | + } else if (splitFp16MultiLargeInnerRoll) { | ||
| 302 | + alignElements = std::max<int64_t>(alignElements, elementsPerBandwidthBlock); | ||
| 303 | + } else if (!splitHugeLeadingDimRoll && !splitHugeTwoWayRoll) { | ||
| 304 | + alignElements = std::max<int64_t>(alignElements, rollBlockElements); | ||
| 305 | + } | ||
| 306 | + const bool splitLargeByInner = | ||
| 307 | + tilingData->activeDimCount == 1 && tilingData->dimNum > 2 && splitHugeLeadingDimRoll && | ||
| 308 | + (xDesc->GetDataType() == ge::DT_UINT8 || xDesc->GetDataType() == ge::DT_INT32) && | ||
| 309 | + totalNum * typeSize >= 16 * 1024 * 1024 && | ||
| 310 | + !(tilingData->dimNum == 2 && tilingData->strides[lastActiveDim] == 10000); | ||
| 311 | + if (splitLargeByInner) { | ||
| 312 | + alignElements = std::max<int64_t>(alignElements, elementsPerBandwidthBlock); | ||
| 313 | + } | ||
| 314 | + } | ||
| 315 | + } | ||
| 316 | + perCoreElements = ((rawPerCore + alignElements - 1) / alignElements) * alignElements; | ||
| 317 | + blockDim = (totalNum + perCoreElements - 1) / perCoreElements; | ||
| 318 | + const bool isTinyTwoDimUint8Last = | ||
| 319 | + xDesc->GetDataType() == ge::DT_UINT8 && tilingData->dimNum == 2 && tilingData->activeDimCount == 1 && | ||
| 320 | + tilingData->activeDim == tilingData->dimNum - 1; | ||
| 321 | + const bool skipSingleCoreForTinyNarrowLast = | ||
| 322 | + isTinyTwoDimUint8Last && | ||
| 323 | + ((totalBytes >= 2048 && totalBytes <= 4096 && tilingData->shapes[tilingData->activeDim] >= 2 && | ||
| 324 | + tilingData->shapes[tilingData->activeDim] <= 8) || | ||
| 325 | + (totalBytes < 2048 && tilingData->shapes[tilingData->activeDim] >= 2 && | ||
| 326 | + tilingData->shapes[tilingData->activeDim] <= 3 && tilingData->shapes[0] >= 64)); | ||
| 327 | + int64_t lastActiveDimForTiny = -1; | ||
| 328 | + for (int64_t dim = 0; dim < tilingData->dimNum; ++dim) { | ||
| 329 | + if (tilingData->shifts[dim] != 0) { | ||
| 330 | + lastActiveDimForTiny = dim; | ||
| 331 | + } | ||
| 332 | + } | ||
| 333 | + const bool skipSingleCoreForTinyBf16Last = | ||
| 334 | + xDesc->GetDataType() == ge::DT_BF16 && tilingData->activeDimCount > 1 && | ||
| 335 | + lastActiveDimForTiny == tilingData->dimNum - 1 && tilingData->shapes[lastActiveDimForTiny] == 3 && | ||
| 336 | + totalBytes >= 512 && totalBytes <= 4096; | ||
| 337 | + if (totalBytes <= 4096 && !skipSingleCoreForTinyNarrowLast && !skipSingleCoreForTinyBf16Last) { | ||
| 338 | + blockDim = 1; | ||
| 339 | + perCoreElements = totalNum; | ||
| 340 | + } | ||
| 341 | + } | ||
| 342 | + tilingData->usedCoreNum = blockDim; | ||
| 343 | + tilingData->perCoreElements = perCoreElements; | ||
| 344 | + tilingData->lastCoreElements = totalNum - (blockDim - 1) * tilingData->perCoreElements; | ||
| 345 | + if (tilingData->lastCoreElements < 0) { | ||
| 346 | + tilingData->lastCoreElements = 0; | ||
| 347 | + } | ||
| 348 | + const int64_t ubElements = std::max<int64_t>(1, UB_BYTES / std::max<int64_t>(typeSize, 1)); | ||
| 349 | + tilingData->ubElements = ubElements; | ||
| 350 | + tilingData->blockFactor = tilingData->perCoreElements; | ||
| 351 | + tilingData->ubFactor = ubElements; | ||
| 352 | + | ||
| 353 | + ret = FillWorkspace(context); | ||
| 354 | + if (ret != ge::GRAPH_SUCCESS) { | ||
| 355 | + return ret; | ||
| 356 | + } | ||
| 357 | + context->SetBlockDim(static_cast<uint32_t>(blockDim)); | ||
| 358 | + context->SetTilingKey(GET_TPL_TILING_KEY(ROLL_TPL_SCH_MODE_0)); | ||
| 359 | + return ge::GRAPH_SUCCESS; | ||
| 360 | +} | ||
| 361 | +} // namespace | ||
| 362 | + | ||
| 363 | +IMPL_OP_OPTILING(Roll).Tiling(RollTiling).TilingParse<RollCompileInfo>(TilingPrepareForRoll); | ||
| 364 | +} // namespace optiling | ||
| @@ -0,0 +1,44 @@ | |||
| 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 roll.cpp | ||
| 13 | + * \brief Roll kernel entry. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +template <typename T> | ||
| 19 | +__aicore__ inline void RunRollKernel(GM_ADDR x, GM_ADDR y, GM_ADDR tiling) | ||
| 20 | +{ | ||
| 21 | + REGISTER_TILING_DEFAULT(RollTilingData); | ||
| 22 | + GET_TILING_DATA_WITH_STRUCT(RollTilingData, tilingData, tiling); | ||
| 23 | + | ||
| 24 | + AscendC::TPipe pipe; | ||
| 25 | + RollKernel::Roll<T> op; | ||
| 26 | + op.Init(x, y, &tilingData, &pipe); | ||
| 27 | + op.Process(); | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +template <uint32_t schMode> | ||
| 31 | +__global__ __aicore__ void roll(GM_ADDR x, GM_ADDR y, GM_ADDR workspace, GM_ADDR tiling) | ||
| 32 | +{ | ||
| 33 | + (void)workspace; | ||
| 34 | + (void)schMode; | ||
| 35 | + KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); | ||
| 36 | + RunRollKernel<DTYPE_X>(x, y, tiling); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +extern "C" __global__ __aicore__ void roll(GM_ADDR x, GM_ADDR y, GM_ADDR workspace, GM_ADDR tiling) | ||
| 40 | +{ | ||
| 41 | + (void)workspace; | ||
| 42 | + KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); | ||
| 43 | + RunRollKernel<DTYPE_X>(x, y, tiling); | ||
| 44 | +} | ||
| @@ -0,0 +1,1198 @@ | |||
| 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 roll.h | ||
| 13 | + * \brief Roll Ascend C kernel. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +namespace RollKernel { | ||
| 24 | +using namespace AscendC; | ||
| 25 | + | ||
| 26 | +constexpr int32_t ROLL_BUFFER_NUM = 1; | ||
| 27 | +constexpr int64_t ROLL_GM_BLOCK_BYTES = 32; | ||
| 28 | +constexpr int64_t ROLL_STRIDED_SEGMENT_MIN_BYTES = 12; | ||
| 29 | +constexpr int64_t ROLL_MAX_DATACOPY_BLOCK_COUNT = 4095; | ||
| 30 | +constexpr int64_t ROLL_FLAT_PATCH_MAX_BLOCK_BYTES = 768; | ||
| 31 | +constexpr int64_t ROLL_FLAT_PATCH_MIN_TOTAL_BYTES = 4096; | ||
| 32 | + | ||
| 33 | +template <typename T> | ||
| 34 | +class Roll { | ||
| 35 | +public: | ||
| 36 | + __aicore__ inline Roll() = default; | ||
| 37 | + __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, const RollTilingData* tilingData, TPipe* pipe); | ||
| 38 | + __aicore__ inline void Process(); | ||
| 39 | + | ||
| 40 | +private: | ||
| 41 | + __aicore__ inline int64_t ComputeSourceRowIndex(int64_t outputRowIndex) const; | ||
| 42 | + __aicore__ inline int64_t ComputeContiguousSourceRowRun(int64_t outputRowIndex, int64_t maxRows) const; | ||
| 43 | + __aicore__ inline int64_t ComputeSourceBlockIndex(int64_t outputBlockIndex, int64_t lastActiveDim) const; | ||
| 44 | + __aicore__ inline int64_t ComputeContiguousSourceBlockRun( | ||
| 45 | + int64_t outputBlockIndex, int64_t maxBlocks, int64_t lastActiveDim) const; | ||
| 46 | + __aicore__ inline int64_t ComputeInputIndex(int64_t outputIndex) const; | ||
| 47 | + __aicore__ inline void CopySegmentByScalar(int64_t dstIndex, int64_t srcIndex, int64_t elementCount); | ||
| 48 | + __aicore__ inline void CopySegmentBySourceAligned(int64_t dstIndex, int64_t srcIndex, int64_t elementCount); | ||
| 49 | + __aicore__ inline void CopyStridedSourceSegments( | ||
| 50 | + int64_t dstIndex, int64_t srcIndex, int64_t segmentElements, int64_t strideElements, int64_t segmentCount); | ||
| 51 | + __aicore__ inline bool CopyStridedSingleElementByRowGather(int64_t dstIndex, | ||
| 52 | + int64_t srcBlockBase, | ||
| 53 | + int64_t sourceOffset, | ||
| 54 | + int64_t blockSize, | ||
| 55 | + int64_t blockCount, | ||
| 56 | + bool preferRowGatherPatch); | ||
| 57 | + __aicore__ inline bool CopyBlockRollByFlatPatch(int64_t dstIndex, | ||
| 58 | + int64_t srcIndex, | ||
| 59 | + int64_t blockSize, | ||
| 60 | + int64_t firstElements, | ||
| 61 | + int64_t secondElements, | ||
| 62 | + int64_t blockCount); | ||
| 63 | + __aicore__ inline void CopySegment(int64_t dstIndex, int64_t srcIndex, int64_t elementCount); | ||
| 64 | + __aicore__ inline void CopyIdentity(); | ||
| 65 | + __aicore__ inline void CopyFlattenRoll(); | ||
| 66 | + __aicore__ inline void CopyFlattenRollBySource(); | ||
| 67 | + __aicore__ inline void CopyLeadingDimRollBySource(); | ||
| 68 | + __aicore__ inline void CopyLastDimRoll(); | ||
| 69 | + __aicore__ inline void CopyLastDimRollByRows(); | ||
| 70 | + __aicore__ inline void CopyLastDimFullRows(int64_t dstIndex, int64_t rowCount); | ||
| 71 | + __aicore__ inline void CopyRowsRollInUb( | ||
| 72 | + LocalTensor<T>& outLocal, LocalTensor<T>& inLocal, int64_t rowCount, int64_t dimSize, | ||
| 73 | + int64_t alignedRowElements, int64_t shift); | ||
| 74 | + __aicore__ inline void CopyLastDimFullRowsBySegments(int64_t dstIndex, int64_t rowCount); | ||
| 75 | + __aicore__ inline void CopyMultiDimLastDimFullRowsFromSource(int64_t dstIndex, int64_t srcRowIndex, int64_t rowCount); | ||
| 76 | + __aicore__ inline void CopyMultiDimLastDimFullRowsBySegments(int64_t dstIndex, int64_t srcRowIndex, int64_t rowCount); | ||
| 77 | + __aicore__ inline void CopyMultiDimLastDimFullRows(int64_t dstIndex, int64_t rowCount); | ||
| 78 | + __aicore__ inline void CopyMultiDimLastDimRollByRows(); | ||
| 79 | + __aicore__ inline void CopyMultiDimNonLastBlockPartial(int64_t lastActiveDim, int64_t& dstIndex, int64_t& remain); | ||
| 80 | + __aicore__ inline void CopyMultiDimNonLastFullBlocks( | ||
| 81 | + int64_t lastActiveDim, int64_t dstIndex, int64_t srcBlockIndex, int64_t blockCount); | ||
| 82 | + __aicore__ inline void CopyMultiDimNonLastRollByBlocks(int64_t lastActiveDim); | ||
| 83 | + __aicore__ inline void CopyLastDimPartial(int64_t& dstIndex, int64_t& remain); | ||
| 84 | + __aicore__ inline void CopySingleDimRoll(); | ||
| 85 | + __aicore__ inline void CopySingleDimRollByBlocks(); | ||
| 86 | + __aicore__ inline void CopySingleDimFullBlocks(int64_t dstIndex, int64_t blockCount); | ||
| 87 | + __aicore__ inline void CopySingleDimPartial(int64_t& dstIndex, int64_t& remain); | ||
| 88 | + __aicore__ inline void CopySegmentedRoll(); | ||
| 89 | + __aicore__ inline void ProcessScalar(); | ||
| 90 | + | ||
| 91 | +private: | ||
| 92 | + TPipe* pipe_ = nullptr; | ||
| 93 | + TQueBind<QuePosition::VECIN, QuePosition::VECOUT, ROLL_BUFFER_NUM> inQueue_; | ||
| 94 | + TQue<QuePosition::VECOUT, ROLL_BUFFER_NUM> outQueue_; | ||
| 95 | + GlobalTensor<T> xGm_; | ||
| 96 | + GlobalTensor<T> yGm_; | ||
| 97 | + const RollTilingData* tilingData_ = nullptr; | ||
| 98 | + int64_t startIndex_ = 0; | ||
| 99 | + int64_t elementCount_ = 0; | ||
| 100 | + int64_t ubElements_ = 1; | ||
| 101 | +}; | ||
| 102 | + | ||
| 103 | +template <typename T> | ||
| 104 | +__aicore__ inline void Roll<T>::Init(GM_ADDR x, GM_ADDR y, const RollTilingData* tilingData, TPipe* pipe) | ||
| 105 | +{ | ||
| 106 | + tilingData_ = tilingData; | ||
| 107 | + pipe_ = pipe; | ||
| 108 | + xGm_.SetGlobalBuffer(reinterpret_cast<__gm__ T*>(x)); | ||
| 109 | + yGm_.SetGlobalBuffer(reinterpret_cast<__gm__ T*>(y)); | ||
| 110 | + | ||
| 111 | + const int64_t blockIdx = static_cast<int64_t>(GetBlockIdx()); | ||
| 112 | + const int64_t perCoreElements = | ||
| 113 | + tilingData_->perCoreElements > 0 ? tilingData_->perCoreElements : tilingData_->blockFactor; | ||
| 114 | + const int64_t lastCoreElements = | ||
| 115 | + tilingData_->lastCoreElements > 0 ? tilingData_->lastCoreElements : perCoreElements; | ||
| 116 | + startIndex_ = blockIdx * perCoreElements; | ||
| 117 | + if (blockIdx >= tilingData_->usedCoreNum) { | ||
| 118 | + elementCount_ = 0; | ||
| 119 | + } else { | ||
| 120 | + elementCount_ = (blockIdx == tilingData_->usedCoreNum - 1) ? lastCoreElements : perCoreElements; | ||
| 121 | + } | ||
| 122 | + if (startIndex_ >= tilingData_->totalNum) { | ||
| 123 | + elementCount_ = 0; | ||
| 124 | + } else if (startIndex_ + elementCount_ > tilingData_->totalNum) { | ||
| 125 | + elementCount_ = tilingData_->totalNum - startIndex_; | ||
| 126 | + } | ||
| 127 | + ubElements_ = tilingData_->ubElements > 0 ? tilingData_->ubElements : tilingData_->ubFactor; | ||
| 128 | + if (ubElements_ <= 0) { | ||
| 129 | + ubElements_ = 1; | ||
| 130 | + } | ||
| 131 | + pipe_->InitBuffer(inQueue_, ROLL_BUFFER_NUM, ubElements_ * sizeof(T)); | ||
| 132 | + pipe_->InitBuffer(outQueue_, ROLL_BUFFER_NUM, ubElements_ * sizeof(T)); | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | +template <typename T> | ||
| 136 | +__aicore__ inline int64_t Roll<T>::ComputeSourceRowIndex(int64_t outputRowIndex) const | ||
| 137 | +{ | ||
| 138 | + int64_t remain = outputRowIndex; | ||
| 139 | + int64_t inputRow = 0; | ||
| 140 | + for (int64_t dim = 0; dim < tilingData_->dimNum - 1; ++dim) { | ||
| 141 | + const int64_t rowStride = tilingData_->strides[dim] / tilingData_->shapes[tilingData_->dimNum - 1]; | ||
| 142 | + const int64_t coord = remain / rowStride; | ||
| 143 | + remain %= rowStride; | ||
| 144 | + const int64_t shape = tilingData_->shapes[dim]; | ||
| 145 | + const int64_t sourceCoord = (coord - tilingData_->shifts[dim] + shape) % shape; | ||
| 146 | + inputRow += sourceCoord * rowStride; | ||
| 147 | + } | ||
| 148 | + return inputRow; | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +template <typename T> | ||
| 152 | +__aicore__ inline int64_t Roll<T>::ComputeContiguousSourceRowRun(int64_t outputRowIndex, int64_t maxRows) const | ||
| 153 | +{ | ||
| 154 | + if (maxRows <= 1) { | ||
| 155 | + return 1; | ||
| 156 | + } | ||
| 157 | + const int64_t lastDimSize = tilingData_->shapes[tilingData_->dimNum - 1]; | ||
| 158 | + int64_t runRows = maxRows; | ||
| 159 | + for (int64_t dim = 0; dim < tilingData_->dimNum - 1; ++dim) { | ||
| 160 | + const int64_t shift = tilingData_->shifts[dim]; | ||
| 161 | + if (shift == 0) { | ||
| 162 | + continue; | ||
| 163 | + } | ||
| 164 | + const int64_t rowStride = tilingData_->strides[dim] / lastDimSize; | ||
| 165 | + if (rowStride <= 0) { | ||
| 166 | + continue; | ||
| 167 | + } | ||
| 168 | + const int64_t shape = tilingData_->shapes[dim]; | ||
| 169 | + const int64_t coord = (outputRowIndex / rowStride) % shape; | ||
| 170 | + const int64_t lowerOffset = outputRowIndex % rowStride; | ||
| 171 | + int64_t contiguous = 0; | ||
| 172 | + if (coord < shift) { | ||
| 173 | + contiguous = (shift - coord) * rowStride - lowerOffset; | ||
| 174 | + } else { | ||
| 175 | + contiguous = (shape - coord) * rowStride - lowerOffset; | ||
| 176 | + } | ||
| 177 | + if (contiguous <= 0) { | ||
| 178 | + contiguous = 1; | ||
| 179 | + } | ||
| 180 | + if (runRows > contiguous) { | ||
| 181 | + runRows = contiguous; | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + return runRows > 0 ? runRows : 1; | ||
| 185 | +} | ||
| 186 | + | ||
| 187 | +template <typename T> | ||
| 188 | +__aicore__ inline int64_t Roll<T>::ComputeSourceBlockIndex(int64_t outputBlockIndex, int64_t lastActiveDim) const | ||
| 189 | +{ | ||
| 190 | + const int64_t blockSize = tilingData_->shapes[lastActiveDim] * tilingData_->strides[lastActiveDim]; | ||
| 191 | + int64_t remain = outputBlockIndex; | ||
| 192 | + int64_t inputBlock = 0; | ||
| 193 | + for (int64_t dim = 0; dim < lastActiveDim; ++dim) { | ||
| 194 | + const int64_t blockStride = tilingData_->strides[dim] / blockSize; | ||
| 195 | + const int64_t coord = remain / blockStride; | ||
| 196 | + remain %= blockStride; | ||
| 197 | + const int64_t shape = tilingData_->shapes[dim]; | ||
| 198 | + const int64_t sourceCoord = (coord - tilingData_->shifts[dim] + shape) % shape; | ||
| 199 | + inputBlock += sourceCoord * blockStride; | ||
| 200 | + } | ||
| 201 | + return inputBlock; | ||
| 202 | +} | ||
| 203 | + | ||
| 204 | +template <typename T> | ||
| 205 | +__aicore__ inline int64_t Roll<T>::ComputeContiguousSourceBlockRun( | ||
| 206 | + int64_t outputBlockIndex, int64_t maxBlocks, int64_t lastActiveDim) const | ||
| 207 | +{ | ||
| 208 | + if (maxBlocks <= 1) { | ||
| 209 | + return 1; | ||
| 210 | + } | ||
| 211 | + const int64_t blockSize = tilingData_->shapes[lastActiveDim] * tilingData_->strides[lastActiveDim]; | ||
| 212 | + int64_t runBlocks = maxBlocks; | ||
| 213 | + for (int64_t dim = 0; dim < lastActiveDim; ++dim) { | ||
| 214 | + const int64_t shift = tilingData_->shifts[dim]; | ||
| 215 | + if (shift == 0) { | ||
| 216 | + continue; | ||
| 217 | + } | ||
| 218 | + const int64_t blockStride = tilingData_->strides[dim] / blockSize; | ||
| 219 | + if (blockStride <= 0) { | ||
| 220 | + continue; | ||
| 221 | + } | ||
| 222 | + const int64_t shape = tilingData_->shapes[dim]; | ||
| 223 | + const int64_t coord = (outputBlockIndex / blockStride) % shape; | ||
| 224 | + const int64_t lowerOffset = outputBlockIndex % blockStride; | ||
| 225 | + int64_t contiguous = 0; | ||
| 226 | + if (coord < shift) { | ||
| 227 | + contiguous = (shift - coord) * blockStride - lowerOffset; | ||
| 228 | + } else { | ||
| 229 | + contiguous = (shape - coord) * blockStride - lowerOffset; | ||
| 230 | + } | ||
| 231 | + if (contiguous <= 0) { | ||
| 232 | + contiguous = 1; | ||
| 233 | + } | ||
| 234 | + if (runBlocks > contiguous) { | ||
| 235 | + runBlocks = contiguous; | ||
| 236 | + } | ||
| 237 | + } | ||
| 238 | + return runBlocks > 0 ? runBlocks : 1; | ||
| 239 | +} | ||
| 240 | + | ||
| 241 | +template <typename T> | ||
| 242 | +__aicore__ inline int64_t Roll<T>::ComputeInputIndex(int64_t outputIndex) const | ||
| 243 | +{ | ||
| 244 | + if (tilingData_->dimNum <= 0 || tilingData_->dimNum > static_cast<int64_t>(ROLL_MAX_DIM_NUM)) { | ||
| 245 | + return outputIndex; | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + int64_t remain = outputIndex; | ||
| 249 | + int64_t inputIndex = 0; | ||
| 250 | + for (int64_t dim = 0; dim < tilingData_->dimNum; ++dim) { | ||
| 251 | + const int64_t stride = tilingData_->strides[dim]; | ||
| 252 | + const int64_t coord = remain / stride; | ||
| 253 | + remain %= stride; | ||
| 254 | + const int64_t shape = tilingData_->shapes[dim]; | ||
| 255 | + const int64_t sourceCoord = (coord - tilingData_->shifts[dim] + shape) % shape; | ||
| 256 | + inputIndex += sourceCoord * stride; | ||
| 257 | + } | ||
| 258 | + return inputIndex; | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +template <typename T> | ||
| 262 | +__aicore__ inline void Roll<T>::CopySegmentByScalar(int64_t dstIndex, int64_t srcIndex, int64_t elementCount) | ||
| 263 | +{ | ||
| 264 | + int64_t copied = 0; | ||
| 265 | + while (copied < elementCount) { | ||
| 266 | + int64_t current = elementCount - copied; | ||
| 267 | + if (current > ubElements_) { | ||
| 268 | + current = ubElements_; | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + LocalTensor<T> local = inQueue_.AllocTensor<T>(); | ||
| 272 | + DataCopyExtParams copyInParams; | ||
| 273 | + copyInParams.blockCount = 1; | ||
| 274 | + copyInParams.blockLen = static_cast<uint32_t>(current * sizeof(T)); | ||
| 275 | + copyInParams.srcStride = 0; | ||
| 276 | + copyInParams.dstStride = 0; | ||
| 277 | + DataCopyPadExtParams<T> padParams{false, 0, 0, static_cast<T>(0)}; | ||
| 278 | + DataCopyPad(local, xGm_[srcIndex + copied], copyInParams, padParams); | ||
| 279 | + inQueue_.EnQue(local); | ||
| 280 | + | ||
| 281 | + LocalTensor<T> result = inQueue_.DeQue<T>(); | ||
| 282 | + DataCopyExtParams copyOutParams; | ||
| 283 | + copyOutParams.blockCount = 1; | ||
| 284 | + copyOutParams.blockLen = static_cast<uint32_t>(current * sizeof(T)); | ||
| 285 | + copyOutParams.srcStride = 0; | ||
| 286 | + copyOutParams.dstStride = 0; | ||
| 287 | + DataCopyPad(yGm_[dstIndex + copied], result, copyOutParams); | ||
| 288 | + inQueue_.FreeTensor(result); | ||
| 289 | + copied += current; | ||
| 290 | + } | ||
| 291 | +} | ||
| 292 | + | ||
| 293 | +template <typename T> | ||
| 294 | +__aicore__ inline void Roll<T>::CopySegmentBySourceAligned(int64_t dstIndex, int64_t srcIndex, int64_t elementCount) | ||
| 295 | +{ | ||
| 296 | + const int64_t typeBytes = static_cast<int64_t>(sizeof(T)); | ||
| 297 | + const int64_t elementsPerBlock = ROLL_GM_BLOCK_BYTES / typeBytes; | ||
| 298 | + int64_t copied = 0; | ||
| 299 | + while (copied < elementCount) { | ||
| 300 | + const int64_t src = srcIndex + copied; | ||
| 301 | + const int64_t srcResidue = src % elementsPerBlock; | ||
| 302 | + if (srcResidue != 0) { | ||
| 303 | + int64_t current = elementsPerBlock - srcResidue; | ||
| 304 | + if (current > elementCount - copied) { | ||
| 305 | + current = elementCount - copied; | ||
| 306 | + } | ||
| 307 | + CopySegmentByScalar(dstIndex + copied, src, current); | ||
| 308 | + copied += current; | ||
| 309 | + continue; | ||
| 310 | + } | ||
| 311 | + | ||
| 312 | + int64_t current = elementCount - copied; | ||
| 313 | + if (current > ubElements_) { | ||
| 314 | + current = ubElements_; | ||
| 315 | + } | ||
| 316 | + LocalTensor<T> local = inQueue_.AllocTensor<T>(); | ||
| 317 | + DataCopyExtParams copyInParams; | ||
| 318 | + copyInParams.blockCount = 1; | ||
| 319 | + copyInParams.blockLen = static_cast<uint32_t>(current * typeBytes); | ||
| 320 | + copyInParams.srcStride = 0; | ||
| 321 | + copyInParams.dstStride = 0; | ||
| 322 | + DataCopyPadExtParams<T> padParams{false, 0, 0, static_cast<T>(0)}; | ||
| 323 | + DataCopyPad(local, xGm_[src], copyInParams, padParams); | ||
| 324 | + inQueue_.EnQue(local); | ||
| 325 | + LocalTensor<T> inLocal = inQueue_.DeQue<T>(); | ||
| 326 | + | ||
| 327 | + DataCopyExtParams copyOutParams; | ||
| 328 | + copyOutParams.blockCount = 1; | ||
| 329 | + copyOutParams.blockLen = static_cast<uint32_t>(current * typeBytes); | ||
| 330 | + copyOutParams.srcStride = 0; | ||
| 331 | + copyOutParams.dstStride = 0; | ||
| 332 | + DataCopyPad(yGm_[dstIndex + copied], inLocal, copyOutParams); | ||
| 333 | + inQueue_.FreeTensor(inLocal); | ||
| 334 | + copied += current; | ||
| 335 | + } | ||
| 336 | +} | ||
| 337 | + | ||
| 338 | +template <typename T> | ||
| 339 | +__aicore__ inline void Roll<T>::CopyStridedSourceSegments( | ||
| 340 | + int64_t dstIndex, int64_t srcIndex, int64_t segmentElements, int64_t strideElements, int64_t segmentCount) | ||
| 341 | +{ | ||
| 342 | + if (segmentElements <= 0 || segmentCount <= 0) { | ||
| 343 | + return; | ||
| 344 | + } | ||
| 345 | + const int64_t typeBytes = static_cast<int64_t>(sizeof(T)); | ||
| 346 | + int64_t copiedSegments = 0; | ||
| 347 | + while (copiedSegments < segmentCount) { | ||
| 348 | + int64_t currentSegments = segmentCount - copiedSegments; | ||
| 349 | + const int64_t maxSegments = ubElements_ / segmentElements; | ||
| 350 | + if (currentSegments > maxSegments) { | ||
| 351 | + currentSegments = maxSegments; | ||
| 352 | + } | ||
| 353 | + if (currentSegments > ROLL_MAX_DATACOPY_BLOCK_COUNT) { | ||
| 354 | + currentSegments = ROLL_MAX_DATACOPY_BLOCK_COUNT; | ||
| 355 | + } | ||
| 356 | + if (currentSegments <= 0) { | ||
| 357 | + currentSegments = 1; | ||
| 358 | + } | ||
| 359 | + | ||
| 360 | + const int64_t curSrc = srcIndex + copiedSegments * strideElements; | ||
| 361 | + const int64_t curDst = dstIndex + copiedSegments * strideElements; | ||
| 362 | + LocalTensor<T> local = inQueue_.AllocTensor<T>(); | ||
| 363 | + DataCopyExtParams copyInParams; | ||
| 364 | + copyInParams.blockCount = static_cast<uint16_t>(currentSegments); | ||
| 365 | + copyInParams.blockLen = static_cast<uint32_t>(segmentElements * typeBytes); | ||
| 366 | + copyInParams.srcStride = static_cast<uint32_t>((strideElements - segmentElements) * typeBytes); | ||
| 367 | + copyInParams.dstStride = 0; | ||
| 368 | + DataCopyPadExtParams<T> padParams{false, 0, 0, static_cast<T>(0)}; | ||
| 369 | + DataCopyPad(local, xGm_[curSrc], copyInParams, padParams); | ||
| 370 | + inQueue_.EnQue(local); | ||
| 371 | + LocalTensor<T> inLocal = inQueue_.DeQue<T>(); | ||
| 372 | + | ||
| 373 | + DataCopyExtParams copyOutParams; | ||
| 374 | + copyOutParams.blockCount = static_cast<uint16_t>(currentSegments); | ||
| 375 | + copyOutParams.blockLen = static_cast<uint32_t>(segmentElements * typeBytes); | ||
| 376 | + copyOutParams.srcStride = 0; | ||
| 377 | + copyOutParams.dstStride = static_cast<uint32_t>((strideElements - segmentElements) * typeBytes); | ||
| 378 | + DataCopyPad(yGm_[curDst], inLocal, copyOutParams); | ||
| 379 | + inQueue_.FreeTensor(inLocal); | ||
| 380 | + copiedSegments += currentSegments; | ||
| 381 | + } | ||
| 382 | +} | ||
| 383 | + | ||
| 384 | +template <typename T> | ||
| 385 | +__aicore__ inline bool Roll<T>::CopyStridedSingleElementByRowGather( | ||
| 386 | + int64_t dstIndex, int64_t srcBlockBase, int64_t sourceOffset, int64_t blockSize, int64_t blockCount, | ||
| 387 | + bool preferRowGatherPatch) | ||
| 388 | +{ | ||
| 389 | + if (!preferRowGatherPatch || sizeof(T) != 1 || blockCount <= 1 || blockSize <= 0 || blockSize > 64 || | ||
| 390 | + sourceOffset < 0 || sourceOffset >= blockSize) { | ||
| 391 | + return false; | ||
| 392 | + } | ||
| 393 | + if (tilingData_->dimNum == 2 && blockSize == 31) { | ||
| 394 | + return false; | ||
| 395 | + } | ||
| 396 | + const bool useRankGt2NarrowLayout = | ||
| 397 | + tilingData_->dimNum > 2 && (blockSize == 7 || (blockSize >= 15 && blockSize <= 31)); | ||
| 398 | + const int64_t alignedBlockElements = | ||
| 399 | + ((blockSize + ROLL_GM_BLOCK_BYTES - 1) / ROLL_GM_BLOCK_BYTES) * ROLL_GM_BLOCK_BYTES; | ||
| 400 | + if (alignedBlockElements <= 0 || alignedBlockElements > ubElements_) { | ||
| 401 | + return false; | ||
| 402 | + } | ||
| 403 | + int64_t maxRows = ubElements_ / alignedBlockElements; | ||
| 404 | + if (maxRows > ubElements_) { | ||
| 405 | + maxRows = ubElements_; | ||
| 406 | + } | ||
| 407 | + if (maxRows > ROLL_MAX_DATACOPY_BLOCK_COUNT) { | ||
| 408 | + maxRows = ROLL_MAX_DATACOPY_BLOCK_COUNT; | ||
| 409 | + } | ||
| 410 | + if (blockSize >= 15 && blockSize <= 31) { | ||
| 411 | + const int64_t rowGatherCap = tilingData_->dimNum == 2 && blockSize == 31 | ||
| 412 | + ? 256 | ||
| 413 | + : (blockSize == 31 ? 384 : (tilingData_->dimNum == 2 ? 512 : 1024)); | ||
| 414 | + if (maxRows > rowGatherCap) { | ||
| 415 | + maxRows = rowGatherCap; | ||
| 416 | + } | ||
| 417 | + } | ||
| 418 | + if (maxRows <= 0) { | ||
| 419 | + return false; | ||
| 420 | + } | ||
| 421 | + | ||
| 422 | + int64_t copiedRows = 0; | ||
| 423 | + while (copiedRows < blockCount) { | ||
| 424 | + int64_t currentRows = blockCount - copiedRows; | ||
| 425 | + if (currentRows > maxRows) { | ||
| 426 | + currentRows = maxRows; | ||
| 427 | + } | ||
| 428 | + LocalTensor<T> local = inQueue_.AllocTensor<T>(); | ||
| 429 | + DataCopyExtParams copyInParams; | ||
| 430 | + copyInParams.blockCount = static_cast<uint16_t>(currentRows); | ||
| 431 | + copyInParams.blockLen = static_cast<uint32_t>(blockSize); | ||
| 432 | + copyInParams.srcStride = 0; | ||
| 433 | + copyInParams.dstStride = 0; | ||
| 434 | + DataCopyPadExtParams<T> padParams{false, 0, 0, static_cast<T>(0)}; | ||
| 435 | + DataCopyPad(local, xGm_[srcBlockBase + copiedRows * blockSize], copyInParams, padParams); | ||
| 436 | + inQueue_.EnQue(local); | ||
| 437 | + LocalTensor<T> inLocal = inQueue_.DeQue<T>(); | ||
| 438 | + | ||
| 439 | + LocalTensor<T> outLocal = outQueue_.AllocTensor<T>(); | ||
| 440 | + auto inPtr = (__ubuf__ T*)inLocal.GetPhyAddr(); | ||
| 441 | + auto outPtr = (__ubuf__ T*)outLocal.GetPhyAddr(); | ||
| 442 | + for (int64_t row = 0; row < currentRows; ++row) { | ||
| 443 | + outPtr[row] = inPtr[row * alignedBlockElements + sourceOffset]; | ||
| 444 | + } | ||
| 445 | + inQueue_.FreeTensor(inLocal); | ||
| 446 | + outQueue_.EnQue(outLocal); | ||
| 447 | + | ||
| 448 | + LocalTensor<T> result = outQueue_.DeQue<T>(); | ||
| 449 | + DataCopyExtParams copyOutParams; | ||
| 450 | + copyOutParams.blockCount = 1; | ||
| 451 | + copyOutParams.blockLen = static_cast<uint32_t>(currentRows * sizeof(T)); | ||
| 452 | + copyOutParams.srcStride = 0; | ||
| 453 | + copyOutParams.dstStride = 0; | ||
| 454 | + DataCopyPad(yGm_[dstIndex + copiedRows], result, copyOutParams); | ||
| 455 | + outQueue_.FreeTensor(result); | ||
| 456 | + copiedRows += currentRows; | ||
| 457 | + } | ||
| 458 | + return true; | ||
| 459 | +} | ||
| 460 | + | ||
| 461 | +template <typename T> | ||
| 462 | +__aicore__ inline bool Roll<T>::CopyBlockRollByFlatPatch( | ||
| 463 | + int64_t dstIndex, int64_t srcIndex, int64_t blockSize, int64_t firstElements, int64_t secondElements, | ||
| 464 | + int64_t blockCount) | ||
| 465 | +{ | ||
| 466 | + const int64_t typeBytes = static_cast<int64_t>(sizeof(T)); | ||
| 467 | + if (blockCount <= 0 || blockSize <= 0 || blockSize > ubElements_ || blockSize * typeBytes > ROLL_FLAT_PATCH_MAX_BLOCK_BYTES || | ||
| 468 | + blockCount * blockSize * typeBytes < ROLL_FLAT_PATCH_MIN_TOTAL_BYTES) { | ||
| 469 | + return false; | ||
| 470 | + } | ||
| 471 | + | ||
| 472 | + const int64_t totalElements = blockCount * blockSize; | ||
| 473 | + LocalTensor<T> local = inQueue_.AllocTensor<T>(); | ||
| 474 | + DataCopyExtParams copyInParams; | ||
| 475 | + copyInParams.blockCount = 1; | ||
| 476 | + copyInParams.blockLen = static_cast<uint32_t>(totalElements * typeBytes); | ||
| 477 | + copyInParams.srcStride = 0; | ||
| 478 | + copyInParams.dstStride = 0; | ||
| 479 | + DataCopyPadExtParams<T> padParams{false, 0, 0, static_cast<T>(0)}; | ||
| 480 | + DataCopyPad(local, xGm_[srcIndex], copyInParams, padParams); | ||
| 481 | + inQueue_.EnQue(local); | ||
| 482 | + LocalTensor<T> inLocal = inQueue_.DeQue<T>(); | ||
| 483 | + | ||
| 484 | + LocalTensor<T> outLocal = outQueue_.AllocTensor<T>(); | ||
| 485 | + auto inPtr = (__ubuf__ T*)inLocal.GetPhyAddr(); | ||
| 486 | + auto outPtr = (__ubuf__ T*)outLocal.GetPhyAddr(); | ||
| 487 | + for (int64_t block = 0; block < blockCount; ++block) { | ||
| 488 | + int64_t base = block * blockSize; | ||
| 489 | + for (int64_t i = 0; i < firstElements; ++i) { | ||
| 490 | + outPtr[base + i] = inPtr[base + secondElements + i]; | ||
| 491 | + } | ||
| 492 | + for (int64_t i = 0; i < secondElements; ++i) { | ||
| 493 | + outPtr[base + firstElements + i] = inPtr[base + i]; | ||
| 494 | + } | ||
| 495 | + } | ||
| 496 | + inQueue_.FreeTensor(inLocal); | ||
| 497 | + outQueue_.EnQue(outLocal); | ||
| 498 | + | ||
| 499 | + LocalTensor<T> result = outQueue_.DeQue<T>(); | ||
| 500 | + DataCopyExtParams copyOutParams; | ||
| 501 | + copyOutParams.blockCount = 1; | ||
| 502 | + copyOutParams.blockLen = static_cast<uint32_t>(totalElements * typeBytes); | ||
| 503 | + copyOutParams.srcStride = 0; | ||
| 504 | + copyOutParams.dstStride = 0; | ||
| 505 | + DataCopyPad(yGm_[dstIndex], result, copyOutParams); | ||
| 506 | + outQueue_.FreeTensor(result); | ||
| 507 | + return true; | ||
| 508 | +} | ||
| 509 | + | ||
| 510 | +template <typename T> | ||
| 511 | +__aicore__ inline void Roll<T>::CopySegment(int64_t dstIndex, int64_t srcIndex, int64_t elementCount) | ||
| 512 | +{ | ||
| 513 | + if (elementCount <= 0) { | ||
| 514 | + return; | ||
| 515 | + } | ||
| 516 | + const int64_t typeBytes = static_cast<int64_t>(sizeof(T)); | ||
| 517 | + const int64_t minStridedBytes = ROLL_STRIDED_SEGMENT_MIN_BYTES > typeBytes ? ROLL_STRIDED_SEGMENT_MIN_BYTES : typeBytes; | ||
| 518 | + if (elementCount * typeBytes >= minStridedBytes) { | ||
| 519 | + CopySegmentBySourceAligned(dstIndex, srcIndex, elementCount); | ||
| 520 | + } else { | ||
| 521 | + CopySegmentByScalar(dstIndex, srcIndex, elementCount); | ||
| 522 | + } | ||
| 523 | +} | ||
| 524 | + | ||
| 525 | +template <typename T> | ||
| 526 | +__aicore__ inline void Roll<T>::CopyIdentity() | ||
| 527 | +{ | ||
| 528 | + CopySegment(startIndex_, startIndex_, elementCount_); | ||
| 529 | +} | ||
| 530 | + | ||
| 531 | +template <typename T> | ||
| 532 | +__aicore__ inline void Roll<T>::CopyFlattenRoll() | ||
| 533 | +{ | ||
| 534 | + CopySegmentedRoll(); | ||
| 535 | +} | ||
| 536 | + | ||
| 537 | +template <typename T> | ||
| 538 | +__aicore__ inline void Roll<T>::CopyFlattenRollBySource() | ||
| 539 | +{ | ||
| 540 | + const int64_t shift = tilingData_->shifts[0]; | ||
| 541 | + const int64_t split = tilingData_->totalNum - shift; | ||
| 542 | + int64_t remain = elementCount_; | ||
| 543 | + int64_t dst = startIndex_; | ||
| 544 | + while (remain > 0) { | ||
| 545 | + int64_t src = 0; | ||
| 546 | + int64_t current = remain; | ||
| 547 | + if (dst < shift) { | ||
| 548 | + src = split + dst; | ||
| 549 | + int64_t boundary = shift - dst; | ||
| 550 | + if (current > boundary) { | ||
| 551 | + current = boundary; | ||
| 552 | + } | ||
| 553 | + } else { | ||
| 554 | + src = dst - shift; | ||
| 555 | + int64_t boundary = tilingData_->totalNum - dst; | ||
| 556 | + if (current > boundary) { | ||
| 557 | + current = boundary; | ||
| 558 | + } | ||
| 559 | + } | ||
| 560 | + CopySegment(dst, src, current); | ||
| 561 | + dst += current; | ||
| 562 | + remain -= current; | ||
| 563 | + } | ||
| 564 | +} | ||
| 565 | + | ||
| 566 | +template <typename T> | ||
| 567 | +__aicore__ inline void Roll<T>::CopyLeadingDimRollBySource() | ||
| 568 | +{ | ||
| 569 | + const int64_t blockSize = tilingData_->dimSize * tilingData_->innerSize; | ||
| 570 | + const int64_t shift = tilingData_->activeShift; | ||
| 571 | + const int64_t split = (tilingData_->dimSize - shift) * tilingData_->innerSize; | ||
| 572 | + int64_t remain = elementCount_; | ||
| 573 | + int64_t dst = startIndex_; | ||
| 574 | + while (remain > 0) { | ||
| 575 | + const int64_t blockOffset = dst % blockSize; | ||
| 576 | + int64_t src = 0; | ||
| 577 | + int64_t current = remain; | ||
| 578 | + if (blockOffset < shift * tilingData_->innerSize) { | ||
| 579 | + src = dst - blockOffset + split + blockOffset; | ||
| 580 | + int64_t boundary = shift * tilingData_->innerSize - blockOffset; | ||
| 581 | + if (current > boundary) { | ||
| 582 | + current = boundary; | ||
| 583 | + } | ||
| 584 | + } else { | ||
| 585 | + src = dst - blockOffset + (blockOffset - shift * tilingData_->innerSize); | ||
| 586 | + int64_t boundary = blockSize - blockOffset; | ||
| 587 | + if (current > boundary) { | ||
| 588 | + current = boundary; | ||
| 589 | + } | ||
| 590 | + } | ||
| 591 | + CopySegment(dst, src, current); | ||
| 592 | + dst += current; | ||
| 593 | + remain -= current; | ||
| 594 | + } | ||
| 595 | +} | ||
| 596 | + | ||
| 597 | +template <typename T> | ||
| 598 | +__aicore__ inline void Roll<T>::CopyLastDimRoll() | ||
| 599 | +{ | ||
| 600 | + CopySegmentedRoll(); | ||
| 601 | +} | ||
| 602 | + | ||
| 603 | +template <typename T> | ||
| 604 | +__aicore__ inline void Roll<T>::CopyLastDimFullRows(int64_t dstIndex, int64_t rowCount) | ||
| 605 | +{ | ||
| 606 | + const int64_t dimSize = tilingData_->dimSize; | ||
| 607 | + const int64_t shift = tilingData_->activeShift; | ||
| 608 | + const int64_t firstElements = shift; | ||
| 609 | + const int64_t secondElements = dimSize - shift; | ||
| 610 | + const int64_t srcBase = (dstIndex / dimSize) * dimSize; | ||
| 611 | + if (CopyBlockRollByFlatPatch(dstIndex, srcBase, dimSize, firstElements, secondElements, rowCount)) { | ||
| 612 | + return; | ||
| 613 | + } | ||
| 614 | + CopyLastDimFullRowsBySegments(dstIndex, rowCount); | ||
| 615 | +} | ||
| 616 | + | ||
| 617 | +template <typename T> | ||
| 618 | +__aicore__ inline void Roll<T>::CopyRowsRollInUb( | ||
| 619 | + LocalTensor<T>& outLocal, LocalTensor<T>& inLocal, int64_t rowCount, int64_t dimSize, | ||
| 620 | + int64_t alignedRowElements, int64_t shift) | ||
| 621 | +{ | ||
| 622 | + auto inPtr = (__ubuf__ T*)inLocal.GetPhyAddr(); | ||
| 623 | + auto outPtr = (__ubuf__ T*)outLocal.GetPhyAddr(); | ||
| 624 | + for (int64_t row = 0; row < rowCount; ++row) { | ||
| 625 | + auto inRow = inPtr + row * alignedRowElements; | ||
| 626 | + auto outRow = outPtr + row * dimSize; | ||
| 627 | + for (int64_t i = 0; i < shift; ++i) { | ||
| 628 | + outRow[i] = inRow[dimSize - shift + i]; | ||
| 629 | + } | ||
| 630 | + for (int64_t i = 0; i < dimSize - shift; ++i) { | ||
| 631 | + outRow[shift + i] = inRow[i]; | ||
| 632 | + } | ||
| 633 | + } | ||
| 634 | +} | ||
| 635 | + | ||
| 636 | +template <typename T> | ||
| 637 | +__aicore__ inline void Roll<T>::CopyLastDimFullRowsBySegments(int64_t dstIndex, int64_t rowCount) | ||
| 638 | +{ | ||
| 639 | + const int64_t dimSize = tilingData_->dimSize; | ||
| 640 | + const int64_t shift = tilingData_->activeShift; | ||
| 641 | + const int64_t firstElements = shift; | ||
| 642 | + const int64_t secondElements = dimSize - shift; | ||
| 643 | + const int64_t srcBase = (dstIndex / dimSize) * dimSize; | ||
| 644 | + CopyStridedSourceSegments(dstIndex, srcBase + secondElements, firstElements, dimSize, rowCount); | ||
| 645 | + CopyStridedSourceSegments(dstIndex + firstElements, srcBase, secondElements, dimSize, rowCount); | ||
| 646 | +} | ||
| 647 | + | ||
| 648 | +template <typename T> | ||
| 649 | +__aicore__ inline void Roll<T>::CopyMultiDimLastDimFullRowsFromSource( | ||
| 650 | + int64_t dstIndex, int64_t srcRowIndex, int64_t rowCount) | ||
| 651 | +{ | ||
| 652 | + const int64_t dimSize = tilingData_->shapes[tilingData_->dimNum - 1]; | ||
| 653 | + const int64_t shift = tilingData_->shifts[tilingData_->dimNum - 1]; | ||
| 654 | + const int64_t typeBytes = static_cast<int64_t>(sizeof(T)); | ||
| 655 | + const int64_t rowBytes = dimSize * typeBytes; | ||
| 656 | + const int64_t alignedRowBytes = ((rowBytes + ROLL_GM_BLOCK_BYTES - 1) / ROLL_GM_BLOCK_BYTES) * ROLL_GM_BLOCK_BYTES; | ||
| 657 | + const int64_t alignedRowElements = alignedRowBytes / typeBytes; | ||
| 658 | + | ||
| 659 | + LocalTensor<T> local = inQueue_.AllocTensor<T>(); | ||
| 660 | + DataCopyExtParams copyInParams; | ||
| 661 | + copyInParams.blockCount = static_cast<uint16_t>(rowCount); | ||
| 662 | + copyInParams.blockLen = static_cast<uint32_t>(rowBytes); | ||
| 663 | + copyInParams.srcStride = 0; | ||
| 664 | + copyInParams.dstStride = 0; | ||
| 665 | + DataCopyPadExtParams<T> padParams{false, 0, 0, static_cast<T>(0)}; | ||
| 666 | + DataCopyPad(local, xGm_[srcRowIndex * dimSize], copyInParams, padParams); | ||
| 667 | + inQueue_.EnQue(local); | ||
| 668 | + LocalTensor<T> inLocal = inQueue_.DeQue<T>(); | ||
| 669 | + | ||
| 670 | + LocalTensor<T> outLocal = outQueue_.AllocTensor<T>(); | ||
| 671 | + CopyRowsRollInUb(outLocal, inLocal, rowCount, dimSize, alignedRowElements, shift); | ||
| 672 | + inQueue_.FreeTensor(inLocal); | ||
| 673 | + outQueue_.EnQue(outLocal); | ||
| 674 | + | ||
| 675 | + LocalTensor<T> result = outQueue_.DeQue<T>(); | ||
| 676 | + DataCopyExtParams copyOutParams; | ||
| 677 | + copyOutParams.blockCount = 1; | ||
| 678 | + copyOutParams.blockLen = static_cast<uint32_t>(rowCount * rowBytes); | ||
| 679 | + copyOutParams.srcStride = 0; | ||
| 680 | + copyOutParams.dstStride = 0; | ||
| 681 | + DataCopyPad(yGm_[dstIndex], result, copyOutParams); | ||
| 682 | + outQueue_.FreeTensor(result); | ||
| 683 | +} | ||
| 684 | + | ||
| 685 | +template <typename T> | ||
| 686 | +__aicore__ inline void Roll<T>::CopyMultiDimLastDimFullRowsBySegments( | ||
| 687 | + int64_t dstIndex, int64_t srcRowIndex, int64_t rowCount) | ||
| 688 | +{ | ||
| 689 | + const int64_t dimSize = tilingData_->shapes[tilingData_->dimNum - 1]; | ||
| 690 | + const int64_t shift = tilingData_->shifts[tilingData_->dimNum - 1]; | ||
| 691 | + const int64_t firstElements = shift; | ||
| 692 | + const int64_t secondElements = dimSize - shift; | ||
| 693 | + const int64_t srcBase = srcRowIndex * dimSize; | ||
| 694 | + if (CopyBlockRollByFlatPatch(dstIndex, srcBase, dimSize, firstElements, secondElements, rowCount)) { | ||
| 695 | + return; | ||
| 696 | + } | ||
| 697 | + CopyStridedSourceSegments(dstIndex, srcBase + secondElements, firstElements, dimSize, rowCount); | ||
| 698 | + CopyStridedSourceSegments(dstIndex + firstElements, srcBase, secondElements, dimSize, rowCount); | ||
| 699 | +} | ||
| 700 | + | ||
| 701 | +template <typename T> | ||
| 702 | +__aicore__ inline void Roll<T>::CopyMultiDimLastDimFullRows(int64_t dstIndex, int64_t rowCount) | ||
| 703 | +{ | ||
| 704 | + const int64_t dimSize = tilingData_->shapes[tilingData_->dimNum - 1]; | ||
| 705 | + const int64_t shift = tilingData_->shifts[tilingData_->dimNum - 1]; | ||
| 706 | + const int64_t typeBytes = static_cast<int64_t>(sizeof(T)); | ||
| 707 | + const int64_t rowBytes = dimSize * typeBytes; | ||
| 708 | + const int64_t alignedRowBytes = ((rowBytes + ROLL_GM_BLOCK_BYTES - 1) / ROLL_GM_BLOCK_BYTES) * ROLL_GM_BLOCK_BYTES; | ||
| 709 | + const int64_t alignedRowElements = alignedRowBytes / typeBytes; | ||
| 710 | + | ||
| 711 | + LocalTensor<T> local = inQueue_.AllocTensor<T>(); | ||
| 712 | + DataCopyExtParams copyInParams; | ||
| 713 | + copyInParams.blockCount = 1; | ||
| 714 | + copyInParams.blockLen = static_cast<uint32_t>(rowBytes); | ||
| 715 | + copyInParams.srcStride = 0; | ||
| 716 | + copyInParams.dstStride = 0; | ||
| 717 | + DataCopyPadExtParams<T> padParams{false, 0, 0, static_cast<T>(0)}; | ||
| 718 | + int64_t copiedRows = 0; | ||
| 719 | + while (copiedRows < rowCount) { | ||
| 720 | + const int64_t dstRow = dstIndex / dimSize + copiedRows; | ||
| 721 | + const int64_t srcRow = ComputeInputIndex(dstRow * dimSize) / dimSize; | ||
| 722 | + int64_t runRows = 1; | ||
| 723 | + while (copiedRows + runRows < rowCount) { | ||
| 724 | + const int64_t nextDstRow = dstRow + runRows; | ||
| 725 | + const int64_t nextSrcRow = ComputeInputIndex(nextDstRow * dimSize) / dimSize; | ||
| 726 | + if (nextSrcRow != srcRow + runRows) { | ||
| 727 | + break; | ||
| 728 | + } | ||
| 729 | + ++runRows; | ||
| 730 | + } | ||
| 731 | + copyInParams.blockCount = static_cast<uint16_t>(runRows); | ||
| 732 | + DataCopyPad(local[copiedRows * alignedRowElements], xGm_[srcRow * dimSize], copyInParams, padParams); | ||
| 733 | + copiedRows += runRows; | ||
| 734 | + } | ||
| 735 | + inQueue_.EnQue(local); | ||
| 736 | + LocalTensor<T> inLocal = inQueue_.DeQue<T>(); | ||
| 737 | + | ||
| 738 | + LocalTensor<T> outLocal = outQueue_.AllocTensor<T>(); | ||
| 739 | + CopyRowsRollInUb(outLocal, inLocal, rowCount, dimSize, alignedRowElements, shift); | ||
| 740 | + inQueue_.FreeTensor(inLocal); | ||
| 741 | + outQueue_.EnQue(outLocal); | ||
| 742 | + | ||
| 743 | + LocalTensor<T> result = outQueue_.DeQue<T>(); | ||
| 744 | + DataCopyExtParams copyOutParams; | ||
| 745 | + copyOutParams.blockCount = 1; | ||
| 746 | + copyOutParams.blockLen = static_cast<uint32_t>(rowCount * rowBytes); | ||
| 747 | + copyOutParams.srcStride = 0; | ||
| 748 | + copyOutParams.dstStride = 0; | ||
| 749 | + DataCopyPad(yGm_[dstIndex], result, copyOutParams); | ||
| 750 | + outQueue_.FreeTensor(result); | ||
| 751 | +} | ||
| 752 | + | ||
| 753 | +template <typename T> | ||
| 754 | +__aicore__ inline void Roll<T>::CopyMultiDimLastDimRollByRows() | ||
| 755 | +{ | ||
| 756 | + const int64_t dimSize = tilingData_->shapes[tilingData_->dimNum - 1]; | ||
| 757 | + const int64_t shift = tilingData_->shifts[tilingData_->dimNum - 1]; | ||
| 758 | + const int64_t typeBytes = static_cast<int64_t>(sizeof(T)); | ||
| 759 | + const int64_t rowBytes = dimSize * typeBytes; | ||
| 760 | + const int64_t alignedRowBytes = ((rowBytes + ROLL_GM_BLOCK_BYTES - 1) / ROLL_GM_BLOCK_BYTES) * ROLL_GM_BLOCK_BYTES; | ||
| 761 | + const int64_t alignedRowElements = alignedRowBytes / typeBytes; | ||
| 762 | + if (dimSize <= 1 || shift <= 0 || alignedRowElements <= 0 || alignedRowElements > ubElements_) { | ||
| 763 | + CopySegmentedRoll(); | ||
| 764 | + return; | ||
| 765 | + } | ||
| 766 | + const int64_t maxInputRows = ubElements_ / alignedRowElements; | ||
| 767 | + const int64_t maxOutputRows = ubElements_ / dimSize; | ||
| 768 | + int64_t maxRows = maxInputRows < maxOutputRows ? maxInputRows : maxOutputRows; | ||
| 769 | + if (maxRows <= 0) { | ||
| 770 | + CopySegmentedRoll(); | ||
| 771 | + return; | ||
| 772 | + } | ||
| 773 | + if (maxRows > 4095) { | ||
| 774 | + maxRows = 4095; | ||
| 775 | + } | ||
| 776 | + | ||
| 777 | + int64_t remain = elementCount_; | ||
| 778 | + int64_t dst = startIndex_; | ||
| 779 | + while (remain > 0 && (dst % dimSize) != 0) { | ||
| 780 | + const int64_t src = ComputeInputIndex(dst); | ||
| 781 | + int64_t current = remain; | ||
| 782 | + const int64_t rowOffset = dst % dimSize; | ||
| 783 | + const int64_t srcOffset = src % dimSize; | ||
| 784 | + const int64_t dstContiguous = dimSize - rowOffset; | ||
| 785 | + const int64_t srcContiguous = dimSize - srcOffset; | ||
| 786 | + if (current > dstContiguous) { | ||
| 787 | + current = dstContiguous; | ||
| 788 | + } | ||
| 789 | + if (current > srcContiguous) { | ||
| 790 | + current = srcContiguous; | ||
| 791 | + } | ||
| 792 | + CopySegment(dst, src, current); | ||
| 793 | + dst += current; | ||
| 794 | + remain -= current; | ||
| 795 | + } | ||
| 796 | + | ||
| 797 | + int64_t fullRows = remain / dimSize; | ||
| 798 | + while (fullRows > 0) { | ||
| 799 | + int64_t currentRows = fullRows > maxRows ? maxRows : fullRows; | ||
| 800 | + if (tilingData_->dimNum == 2) { | ||
| 801 | + const int64_t outerSize = tilingData_->shapes[0]; | ||
| 802 | + const int64_t rowShift = tilingData_->shifts[0]; | ||
| 803 | + const int64_t dstRow = dst / dimSize; | ||
| 804 | + int64_t srcRow = dstRow - rowShift; | ||
| 805 | + if (srcRow < 0) { | ||
| 806 | + srcRow += outerSize; | ||
| 807 | + } | ||
| 808 | + const int64_t srcContiguousRows = outerSize - srcRow; | ||
| 809 | + if (currentRows > srcContiguousRows) { | ||
| 810 | + currentRows = srcContiguousRows; | ||
| 811 | + } | ||
| 812 | + if (IsSameType<T, bfloat16_t>::value && tilingData_->activeDimCount > 1 && dimSize == 3 && rowShift != 0 && | ||
| 813 | + shift != 0 && tilingData_->totalNum * static_cast<int64_t>(sizeof(T)) >= 512 && | ||
| 814 | + tilingData_->totalNum * static_cast<int64_t>(sizeof(T)) <= 4096) { | ||
| 815 | + CopyMultiDimLastDimFullRowsFromSource(dst, srcRow, currentRows); | ||
| 816 | + } else { | ||
| 817 | + CopyMultiDimLastDimFullRowsBySegments(dst, srcRow, currentRows); | ||
| 818 | + } | ||
| 819 | + } else { | ||
| 820 | + const int64_t dstRow = dst / dimSize; | ||
| 821 | + int64_t srcRow = ComputeSourceRowIndex(dstRow); | ||
| 822 | + currentRows = ComputeContiguousSourceRowRun(dstRow, currentRows); | ||
| 823 | + CopyMultiDimLastDimFullRowsBySegments(dst, srcRow, currentRows); | ||
| 824 | + } | ||
| 825 | + const int64_t copied = currentRows * dimSize; | ||
| 826 | + dst += copied; | ||
| 827 | + remain -= copied; | ||
| 828 | + fullRows -= currentRows; | ||
| 829 | + } | ||
| 830 | + | ||
| 831 | + while (remain > 0) { | ||
| 832 | + const int64_t src = ComputeInputIndex(dst); | ||
| 833 | + int64_t current = remain; | ||
| 834 | + const int64_t rowOffset = dst % dimSize; | ||
| 835 | + const int64_t srcOffset = src % dimSize; | ||
| 836 | + const int64_t dstContiguous = dimSize - rowOffset; | ||
| 837 | + const int64_t srcContiguous = dimSize - srcOffset; | ||
| 838 | + if (current > dstContiguous) { | ||
| 839 | + current = dstContiguous; | ||
| 840 | + } | ||
| 841 | + if (current > srcContiguous) { | ||
| 842 | + current = srcContiguous; | ||
| 843 | + } | ||
| 844 | + CopySegment(dst, src, current); | ||
| 845 | + dst += current; | ||
| 846 | + remain -= current; | ||
| 847 | + } | ||
| 848 | +} | ||
| 849 | + | ||
| 850 | +template <typename T> | ||
| 851 | +__aicore__ inline void Roll<T>::CopyMultiDimNonLastBlockPartial( | ||
| 852 | + int64_t lastActiveDim, int64_t& dstIndex, int64_t& remain) | ||
| 853 | +{ | ||
| 854 | + const int64_t inner = tilingData_->strides[lastActiveDim]; | ||
| 855 | + const int64_t dimSize = tilingData_->shapes[lastActiveDim]; | ||
| 856 | + const int64_t shift = tilingData_->shifts[lastActiveDim]; | ||
| 857 | + const int64_t blockSize = dimSize * inner; | ||
| 858 | + const int64_t firstElements = shift * inner; | ||
| 859 | + const int64_t secondElements = (dimSize - shift) * inner; | ||
| 860 | + | ||
| 861 | + const int64_t dstBlock = dstIndex / blockSize; | ||
| 862 | + const int64_t srcBlock = ComputeSourceBlockIndex(dstBlock, lastActiveDim); | ||
| 863 | + const int64_t inBlockOffset = dstIndex % blockSize; | ||
| 864 | + int64_t src = 0; | ||
| 865 | + int64_t contiguous = 0; | ||
| 866 | + if (inBlockOffset < firstElements) { | ||
| 867 | + src = srcBlock * blockSize + secondElements + inBlockOffset; | ||
| 868 | + contiguous = firstElements - inBlockOffset; | ||
| 869 | + } else { | ||
| 870 | + src = srcBlock * blockSize + inBlockOffset - firstElements; | ||
| 871 | + contiguous = blockSize - inBlockOffset; | ||
| 872 | + } | ||
| 873 | + int64_t current = remain; | ||
| 874 | + if (current > contiguous) { | ||
| 875 | + current = contiguous; | ||
| 876 | + } | ||
| 877 | + CopySegment(dstIndex, src, current); | ||
| 878 | + dstIndex += current; | ||
| 879 | + remain -= current; | ||
| 880 | +} | ||
| 881 | + | ||
| 882 | +template <typename T> | ||
| 883 | +__aicore__ inline void Roll<T>::CopyMultiDimNonLastFullBlocks( | ||
| 884 | + int64_t lastActiveDim, int64_t dstIndex, int64_t srcBlockIndex, int64_t blockCount) | ||
| 885 | +{ | ||
| 886 | + const int64_t inner = tilingData_->strides[lastActiveDim]; | ||
| 887 | + const int64_t dimSize = tilingData_->shapes[lastActiveDim]; | ||
| 888 | + const int64_t shift = tilingData_->shifts[lastActiveDim]; | ||
| 889 | + const int64_t blockSize = dimSize * inner; | ||
| 890 | + const int64_t firstElements = shift * inner; | ||
| 891 | + const int64_t secondElements = (dimSize - shift) * inner; | ||
| 892 | + const int64_t srcIndex = srcBlockIndex * blockSize; | ||
| 893 | + if (CopyBlockRollByFlatPatch(dstIndex, srcIndex, blockSize, firstElements, secondElements, blockCount)) { | ||
| 894 | + return; | ||
| 895 | + } | ||
| 896 | + if (firstElements <= ubElements_ && secondElements <= ubElements_) { | ||
| 897 | + CopyStridedSourceSegments(dstIndex, srcIndex + secondElements, firstElements, blockSize, blockCount); | ||
| 898 | + CopyStridedSourceSegments(dstIndex + firstElements, srcIndex, secondElements, blockSize, blockCount); | ||
| 899 | + return; | ||
| 900 | + } | ||
| 901 | + int64_t copiedBlocks = 0; | ||
| 902 | + while (copiedBlocks < blockCount) { | ||
| 903 | + const int64_t dst = dstIndex + copiedBlocks * blockSize; | ||
| 904 | + const int64_t src = srcIndex + copiedBlocks * blockSize; | ||
| 905 | + CopySegment(dst, src + secondElements, firstElements); | ||
| 906 | + CopySegment(dst + firstElements, src, secondElements); | ||
| 907 | + ++copiedBlocks; | ||
| 908 | + } | ||
| 909 | +} | ||
| 910 | + | ||
| 911 | +template <typename T> | ||
| 912 | +__aicore__ inline void Roll<T>::CopyMultiDimNonLastRollByBlocks(int64_t lastActiveDim) | ||
| 913 | +{ | ||
| 914 | + const int64_t inner = tilingData_->strides[lastActiveDim]; | ||
| 915 | + const int64_t dimSize = tilingData_->shapes[lastActiveDim]; | ||
| 916 | + const int64_t shift = tilingData_->shifts[lastActiveDim]; | ||
| 917 | + const int64_t blockSize = dimSize * inner; | ||
| 918 | + if (inner <= 0 || dimSize <= 1 || shift <= 0 || blockSize <= 0) { | ||
| 919 | + CopySegmentedRoll(); | ||
| 920 | + return; | ||
| 921 | + } | ||
| 922 | + | ||
| 923 | + int64_t remain = elementCount_; | ||
| 924 | + int64_t dst = startIndex_; | ||
| 925 | + while (remain > 0 && (dst % blockSize) != 0) { | ||
| 926 | + CopyMultiDimNonLastBlockPartial(lastActiveDim, dst, remain); | ||
| 927 | + } | ||
| 928 | + | ||
| 929 | + int64_t fullBlocks = remain / blockSize; | ||
| 930 | + while (fullBlocks > 0) { | ||
| 931 | + const int64_t dstBlock = dst / blockSize; | ||
| 932 | + int64_t srcBlock = ComputeSourceBlockIndex(dstBlock, lastActiveDim); | ||
| 933 | + int64_t runBlocks = ComputeContiguousSourceBlockRun(dstBlock, fullBlocks, lastActiveDim); | ||
| 934 | + if (runBlocks > 4095) { | ||
| 935 | + runBlocks = 4095; | ||
| 936 | + } | ||
| 937 | + CopyMultiDimNonLastFullBlocks(lastActiveDim, dst, srcBlock, runBlocks); | ||
| 938 | + const int64_t copied = runBlocks * blockSize; | ||
| 939 | + dst += copied; | ||
| 940 | + remain -= copied; | ||
| 941 | + fullBlocks -= runBlocks; | ||
| 942 | + } | ||
| 943 | + | ||
| 944 | + while (remain > 0) { | ||
| 945 | + CopyMultiDimNonLastBlockPartial(lastActiveDim, dst, remain); | ||
| 946 | + } | ||
| 947 | +} | ||
| 948 | + | ||
| 949 | +template <typename T> | ||
| 950 | +__aicore__ inline void Roll<T>::CopyLastDimPartial(int64_t& dstIndex, int64_t& remain) | ||
| 951 | +{ | ||
| 952 | + const int64_t dimSize = tilingData_->dimSize; | ||
| 953 | + const int64_t shift = tilingData_->activeShift; | ||
| 954 | + const int64_t secondElements = dimSize - shift; | ||
| 955 | + const int64_t rowBase = (dstIndex / dimSize) * dimSize; | ||
| 956 | + const int64_t rowOffset = dstIndex % dimSize; | ||
| 957 | + int64_t src = 0; | ||
| 958 | + int64_t contiguous = 0; | ||
| 959 | + if (rowOffset < shift) { | ||
| 960 | + src = rowBase + secondElements + rowOffset; | ||
| 961 | + contiguous = shift - rowOffset; | ||
| 962 | + } else { | ||
| 963 | + src = rowBase + rowOffset - shift; | ||
| 964 | + contiguous = dimSize - rowOffset; | ||
| 965 | + } | ||
| 966 | + int64_t current = remain; | ||
| 967 | + if (current > contiguous) { | ||
| 968 | + current = contiguous; | ||
| 969 | + } | ||
| 970 | + CopySegment(dstIndex, src, current); | ||
| 971 | + dstIndex += current; | ||
| 972 | + remain -= current; | ||
| 973 | +} | ||
| 974 | + | ||
| 975 | +template <typename T> | ||
| 976 | +__aicore__ inline void Roll<T>::CopySingleDimRoll() | ||
| 977 | +{ | ||
| 978 | + CopySegmentedRoll(); | ||
| 979 | +} | ||
| 980 | + | ||
| 981 | +template <typename T> | ||
| 982 | +__aicore__ inline void Roll<T>::CopySingleDimFullBlocks(int64_t dstIndex, int64_t blockCount) | ||
| 983 | +{ | ||
| 984 | + const int64_t blockSize = tilingData_->dimSize * tilingData_->innerSize; | ||
| 985 | + const int64_t firstElements = tilingData_->activeShift * tilingData_->innerSize; | ||
| 986 | + const int64_t secondElements = blockSize - firstElements; | ||
| 987 | + const int64_t srcIndex = ComputeInputIndex(dstIndex); | ||
| 988 | + if (CopyBlockRollByFlatPatch(dstIndex, srcIndex, blockSize, firstElements, secondElements, blockCount)) { | ||
| 989 | + return; | ||
| 990 | + } | ||
| 991 | + CopyStridedSourceSegments(dstIndex, srcIndex + secondElements, firstElements, blockSize, blockCount); | ||
| 992 | + CopyStridedSourceSegments(dstIndex + firstElements, srcIndex, secondElements, blockSize, blockCount); | ||
| 993 | +} | ||
| 994 | + | ||
| 995 | +template <typename T> | ||
| 996 | +__aicore__ inline void Roll<T>::CopySingleDimPartial(int64_t& dstIndex, int64_t& remain) | ||
| 997 | +{ | ||
| 998 | + const int64_t blockSize = tilingData_->dimSize * tilingData_->innerSize; | ||
| 999 | + const int64_t firstElements = tilingData_->activeShift * tilingData_->innerSize; | ||
| 1000 | + const int64_t secondElements = blockSize - firstElements; | ||
| 1001 | + const int64_t blockOffset = dstIndex % blockSize; | ||
| 1002 | + int64_t src = 0; | ||
| 1003 | + int64_t contiguous = 0; | ||
| 1004 | + if (blockOffset < firstElements) { | ||
| 1005 | + src = dstIndex - blockOffset + secondElements + blockOffset; | ||
| 1006 | + contiguous = firstElements - blockOffset; | ||
| 1007 | + } else { | ||
| 1008 | + src = dstIndex - blockOffset + blockOffset - firstElements; | ||
| 1009 | + contiguous = blockSize - blockOffset; | ||
| 1010 | + } | ||
| 1011 | + int64_t current = remain; | ||
| 1012 | + if (current > contiguous) { | ||
| 1013 | + current = contiguous; | ||
| 1014 | + } | ||
| 1015 | + CopySegment(dstIndex, src, current); | ||
| 1016 | + dstIndex += current; | ||
| 1017 | + remain -= current; | ||
| 1018 | +} | ||
| 1019 | + | ||
| 1020 | +template <typename T> | ||
| 1021 | +__aicore__ inline void Roll<T>::CopySingleDimRollByBlocks() | ||
| 1022 | +{ | ||
| 1023 | + const int64_t blockSize = tilingData_->dimSize * tilingData_->innerSize; | ||
| 1024 | + if (blockSize <= 0 || tilingData_->activeShift <= 0 || tilingData_->dimSize <= 1) { | ||
| 1025 | + CopySingleDimRoll(); | ||
| 1026 | + return; | ||
| 1027 | + } | ||
| 1028 | + | ||
| 1029 | + int64_t remain = elementCount_; | ||
| 1030 | + int64_t dst = startIndex_; | ||
| 1031 | + while (remain > 0 && (dst % blockSize) != 0) { | ||
| 1032 | + CopySingleDimPartial(dst, remain); | ||
| 1033 | + } | ||
| 1034 | + | ||
| 1035 | + int64_t fullBlocks = remain / blockSize; | ||
| 1036 | + while (fullBlocks > 0) { | ||
| 1037 | + int64_t currentBlocks = fullBlocks > 4095 ? 4095 : fullBlocks; | ||
| 1038 | + CopySingleDimFullBlocks(dst, currentBlocks); | ||
| 1039 | + const int64_t copied = currentBlocks * blockSize; | ||
| 1040 | + dst += copied; | ||
| 1041 | + remain -= copied; | ||
| 1042 | + fullBlocks -= currentBlocks; | ||
| 1043 | + } | ||
| 1044 | + | ||
| 1045 | + while (remain > 0) { | ||
| 1046 | + CopySingleDimPartial(dst, remain); | ||
| 1047 | + } | ||
| 1048 | +} | ||
| 1049 | + | ||
| 1050 | +template <typename T> | ||
| 1051 | +__aicore__ inline void Roll<T>::CopyLastDimRollByRows() | ||
| 1052 | +{ | ||
| 1053 | + const int64_t dimSize = tilingData_->dimSize; | ||
| 1054 | + const int64_t shift = tilingData_->activeShift; | ||
| 1055 | + const int64_t typeBytes = static_cast<int64_t>(sizeof(T)); | ||
| 1056 | + const int64_t rowBytes = dimSize * typeBytes; | ||
| 1057 | + const int64_t alignedRowBytes = ((rowBytes + ROLL_GM_BLOCK_BYTES - 1) / ROLL_GM_BLOCK_BYTES) * ROLL_GM_BLOCK_BYTES; | ||
| 1058 | + const int64_t alignedRowElements = alignedRowBytes / typeBytes; | ||
| 1059 | + if (dimSize <= 1 || shift <= 0 || alignedRowElements <= 0 || alignedRowElements > ubElements_) { | ||
| 1060 | + CopyLastDimRoll(); | ||
| 1061 | + return; | ||
| 1062 | + } | ||
| 1063 | + | ||
| 1064 | + const int64_t maxInputRows = ubElements_ / alignedRowElements; | ||
| 1065 | + const int64_t maxOutputRows = ubElements_ / dimSize; | ||
| 1066 | + int64_t maxRows = maxInputRows < maxOutputRows ? maxInputRows : maxOutputRows; | ||
| 1067 | + if (maxRows <= 0) { | ||
| 1068 | + CopyLastDimRoll(); | ||
| 1069 | + return; | ||
| 1070 | + } | ||
| 1071 | + if (maxRows > 4095) { | ||
| 1072 | + maxRows = 4095; | ||
| 1073 | + } | ||
| 1074 | + | ||
| 1075 | + int64_t remain = elementCount_; | ||
| 1076 | + int64_t dst = startIndex_; | ||
| 1077 | + while (remain > 0 && (dst % dimSize) != 0) { | ||
| 1078 | + CopyLastDimPartial(dst, remain); | ||
| 1079 | + } | ||
| 1080 | + | ||
| 1081 | + int64_t fullRows = remain / dimSize; | ||
| 1082 | + while (fullRows > 0) { | ||
| 1083 | + int64_t currentRows = fullRows > maxRows ? maxRows : fullRows; | ||
| 1084 | + const int64_t tailElements = dimSize - shift; | ||
| 1085 | + const int64_t largeSegmentBytes = (shift > tailElements ? shift : tailElements) * typeBytes; | ||
| 1086 | + const bool preferSegmentPath = (largeSegmentBytes >= ROLL_STRIDED_SEGMENT_MIN_BYTES) || | ||
| 1087 | + (sizeof(T) == 1 && dimSize >= 7 && dimSize <= 31); | ||
| 1088 | + if (preferSegmentPath) { | ||
| 1089 | + CopyLastDimFullRowsBySegments(dst, currentRows); | ||
| 1090 | + } else { | ||
| 1091 | + CopyLastDimFullRows(dst, currentRows); | ||
| 1092 | + } | ||
| 1093 | + const int64_t copied = currentRows * dimSize; | ||
| 1094 | + dst += copied; | ||
| 1095 | + remain -= copied; | ||
| 1096 | + fullRows -= currentRows; | ||
| 1097 | + } | ||
| 1098 | + | ||
| 1099 | + while (remain > 0) { | ||
| 1100 | + CopyLastDimPartial(dst, remain); | ||
| 1101 | + } | ||
| 1102 | +} | ||
| 1103 | + | ||
| 1104 | +template <typename T> | ||
| 1105 | +__aicore__ inline void Roll<T>::CopySegmentedRoll() | ||
| 1106 | +{ | ||
| 1107 | + int64_t lastActiveDim = -1; | ||
| 1108 | + for (int64_t dim = 0; dim < tilingData_->dimNum; ++dim) { | ||
| 1109 | + if (tilingData_->shifts[dim] != 0) { | ||
| 1110 | + lastActiveDim = dim; | ||
| 1111 | + } | ||
| 1112 | + } | ||
| 1113 | + if (lastActiveDim < 0) { | ||
| 1114 | + CopyIdentity(); | ||
| 1115 | + return; | ||
| 1116 | + } | ||
| 1117 | + | ||
| 1118 | + int64_t remain = elementCount_; | ||
| 1119 | + int64_t dst = startIndex_; | ||
| 1120 | + while (remain > 0) { | ||
| 1121 | + const int64_t src = ComputeInputIndex(dst); | ||
| 1122 | + int64_t current = remain; | ||
| 1123 | + if (lastActiveDim == tilingData_->dimNum - 1) { | ||
| 1124 | + const int64_t dimSize = tilingData_->shapes[lastActiveDim]; | ||
| 1125 | + const int64_t shift = tilingData_->shifts[lastActiveDim]; | ||
| 1126 | + const int64_t dstOffset = dst % dimSize; | ||
| 1127 | + const int64_t srcOffset = (dstOffset - shift + dimSize) % dimSize; | ||
| 1128 | + const int64_t dstContiguous = dimSize - dstOffset; | ||
| 1129 | + const int64_t srcContiguous = dimSize - srcOffset; | ||
| 1130 | + if (current > dstContiguous) { | ||
| 1131 | + current = dstContiguous; | ||
| 1132 | + } | ||
| 1133 | + if (current > srcContiguous) { | ||
| 1134 | + current = srcContiguous; | ||
| 1135 | + } | ||
| 1136 | + } else { | ||
| 1137 | + const int64_t contiguous = tilingData_->strides[lastActiveDim]; | ||
| 1138 | + const int64_t offset = dst % contiguous; | ||
| 1139 | + const int64_t dstContiguous = contiguous - offset; | ||
| 1140 | + if (current > dstContiguous) { | ||
| 1141 | + current = dstContiguous; | ||
| 1142 | + } | ||
| 1143 | + } | ||
| 1144 | + CopySegment(dst, src, current); | ||
| 1145 | + dst += current; | ||
| 1146 | + remain -= current; | ||
| 1147 | + } | ||
| 1148 | +} | ||
| 1149 | + | ||
| 1150 | +template <typename T> | ||
| 1151 | +__aicore__ inline void Roll<T>::ProcessScalar() | ||
| 1152 | +{ | ||
| 1153 | + CopySegmentedRoll(); | ||
| 1154 | +} | ||
| 1155 | + | ||
| 1156 | +template <typename T> | ||
| 1157 | +__aicore__ inline void Roll<T>::Process() | ||
| 1158 | +{ | ||
| 1159 | + if (elementCount_ <= 0 || tilingData_->totalNum <= 0) { | ||
| 1160 | + return; | ||
| 1161 | + } | ||
| 1162 | + if (tilingData_->activeDimCount == 0) { | ||
| 1163 | + CopyIdentity(); | ||
| 1164 | + } else if (tilingData_->dimNum == 1 && tilingData_->strides[0] == 1) { | ||
| 1165 | + CopyFlattenRollBySource(); | ||
| 1166 | + } else if (tilingData_->activeDimCount == 1 && tilingData_->activeDim == 0 && tilingData_->innerSize > 0 && | ||
| 1167 | + (tilingData_->dimNum == 2 || tilingData_->dimSize <= 4 || | ||
| 1168 | + (IsSameType<T, uint8_t>::value && tilingData_->dimNum > 2 && | ||
| 1169 | + tilingData_->innerSize % ROLL_GM_BLOCK_BYTES == 0 && | ||
| 1170 | + tilingData_->totalNum >= 32 * 1024 * 1024)) && | ||
| 1171 | + !(sizeof(T) == 1 && tilingData_->dimNum == 2 && tilingData_->innerSize == 127)) { | ||
| 1172 | + CopyLeadingDimRollBySource(); | ||
| 1173 | + } else if (tilingData_->activeDimCount == 1 && tilingData_->innerSize == 1 && | ||
| 1174 | + tilingData_->activeDim == tilingData_->dimNum - 1) { | ||
| 1175 | + CopyLastDimRollByRows(); | ||
| 1176 | + } else if (tilingData_->activeDimCount == 1 && tilingData_->innerSize > 0) { | ||
| 1177 | + CopySingleDimRollByBlocks(); | ||
| 1178 | + } else { | ||
| 1179 | + int64_t lastActiveDim = -1; | ||
| 1180 | + for (int64_t dim = 0; dim < tilingData_->dimNum; ++dim) { | ||
| 1181 | + if (tilingData_->shifts[dim] != 0) { | ||
| 1182 | + lastActiveDim = dim; | ||
| 1183 | + } | ||
| 1184 | + } | ||
| 1185 | + if (lastActiveDim == tilingData_->dimNum - 1) { | ||
| 1186 | + CopyMultiDimLastDimRollByRows(); | ||
| 1187 | + return; | ||
| 1188 | + } else if (lastActiveDim >= 0) { | ||
| 1189 | + CopyMultiDimNonLastRollByBlocks(lastActiveDim); | ||
| 1190 | + return; | ||
| 1191 | + } | ||
| 1192 | + CopySegmentedRoll(); | ||
| 1193 | + } | ||
| 1194 | +} | ||
| 1195 | + | ||
| 1196 | +} // namespace RollKernel | ||
| 1197 | + | ||
| 1198 | + | ||
| @@ -0,0 +1,44 @@ | |||
| 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 roll_tiling_data.h | ||
| 13 | + * \brief Roll tiling data. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +constexpr uint32_t ROLL_MAX_DIM_NUM = 8; | ||
| 22 | + | ||
| 23 | +struct RollTilingData { | ||
| 24 | + int64_t totalNum = 0; | ||
| 25 | + int64_t dimNum = 0; | ||
| 26 | + int64_t perCoreElements = 0; | ||
| 27 | + int64_t lastCoreElements = 0; | ||
| 28 | + int64_t usedCoreNum = 1; | ||
| 29 | + int64_t ubElements = 0; | ||
| 30 | + int64_t blockFactor = 0; | ||
| 31 | + int64_t ubFactor = 0; | ||
| 32 | + int64_t activeDimCount = 0; | ||
| 33 | + int64_t activeDim = -1; | ||
| 34 | + int64_t outerSize = 0; | ||
| 35 | + int64_t dimSize = 0; | ||
| 36 | + int64_t innerSize = 0; | ||
| 37 | + int64_t activeShift = 0; | ||
| 38 | + int64_t useSafeUbShuffle = 0; | ||
| 39 | + int64_t shapes[ROLL_MAX_DIM_NUM] = {0}; | ||
| 40 | + int64_t strides[ROLL_MAX_DIM_NUM] = {0}; | ||
| 41 | + int64_t shifts[ROLL_MAX_DIM_NUM] = {0}; | ||
| 42 | +}; | ||
| 43 | + | ||
| 44 | + | ||
| @@ -0,0 +1,31 @@ | |||
| 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 roll_tiling_key.h | ||
| 13 | + * \brief Tiling template argument declaration. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +ASCENDC_TPL_ARGS_DECL( | ||
| 25 | + Roll, | ||
| 26 | + ASCENDC_TPL_UINT_DECL(schMode, 1, ASCENDC_TPL_UI_LIST, ROLL_TPL_SCH_MODE_0, ROLL_TPL_SCH_MODE_1)); | ||
| 27 | + | ||
| 28 | +ASCENDC_TPL_SEL(ASCENDC_TPL_ARGS_SEL( | ||
| 29 | + ASCENDC_TPL_UINT_SEL(schMode, ASCENDC_TPL_UI_LIST, ROLL_TPL_SCH_MODE_0, ROLL_TPL_SCH_MODE_1))); | ||
| 30 | + | ||
| 31 | + | ||
| @@ -0,0 +1,16 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 13 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 14 | + add_subdirectory(${SUB_DIR}) | ||
| 15 | + endif() | ||
| 16 | +endforeach() | ||
| @@ -0,0 +1,16 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 13 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 14 | + add_subdirectory(${SUB_DIR}) | ||
| 15 | + endif() | ||
| 16 | +endforeach() | ||
| @@ -0,0 +1,80 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +using namespace op; | ||
| 21 | + | ||
| 22 | +class test_aclnn_roll : public testing::Test { | ||
| 23 | +protected: | ||
| 24 | + static void SetUpTestCase() | ||
| 25 | + { | ||
| 26 | + op::SetPlatformSocVersion(op::SocVersion::ASCEND910B); | ||
| 27 | + } | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | +TEST_F(test_aclnn_roll, case_basic_float) | ||
| 31 | +{ | ||
| 32 | + auto xDesc = TensorDesc({2, 3}, ACL_FLOAT, ACL_FORMAT_ND).Value(std::vector<float>{0, 1, 2, 3, 4, 5}); | ||
| 33 | + auto yDesc = TensorDesc({2, 3}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0, 0.0); | ||
| 34 | + auto shifts = IntArrayDesc(std::vector<int64_t>{1}); | ||
| 35 | + auto dims = IntArrayDesc(std::vector<int64_t>{1}); | ||
| 36 | + | ||
| 37 | + auto ut = OP_API_UT(aclnnRoll, INPUT(xDesc, shifts, dims), OUTPUT(yDesc)); | ||
| 38 | + uint64_t workspaceSize = 0; | ||
| 39 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspaceSize); | ||
| 40 | + EXPECT_EQ(aclRet, ACLNN_SUCCESS); | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +TEST_F(test_aclnn_roll, case_dims_empty) | ||
| 44 | +{ | ||
| 45 | + auto xDesc = TensorDesc({2, 3}, ACL_FLOAT16, ACL_FORMAT_ND); | ||
| 46 | + auto yDesc = TensorDesc({2, 3}, ACL_FLOAT16, ACL_FORMAT_ND); | ||
| 47 | + auto shifts = IntArrayDesc(std::vector<int64_t>{2}); | ||
| 48 | + auto dims = IntArrayDesc(std::vector<int64_t>{}); | ||
| 49 | + | ||
| 50 | + auto ut = OP_API_UT(aclnnRoll, INPUT(xDesc, shifts, dims), OUTPUT(yDesc)); | ||
| 51 | + uint64_t workspaceSize = 0; | ||
| 52 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspaceSize); | ||
| 53 | + EXPECT_EQ(aclRet, ACLNN_SUCCESS); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +TEST_F(test_aclnn_roll, case_invalid_dtype) | ||
| 57 | +{ | ||
| 58 | + auto xDesc = TensorDesc({4}, ACL_DOUBLE, ACL_FORMAT_ND); | ||
| 59 | + auto yDesc = TensorDesc({4}, ACL_DOUBLE, ACL_FORMAT_ND); | ||
| 60 | + auto shifts = IntArrayDesc(std::vector<int64_t>{1}); | ||
| 61 | + auto dims = IntArrayDesc(std::vector<int64_t>{0}); | ||
| 62 | + | ||
| 63 | + auto ut = OP_API_UT(aclnnRoll, INPUT(xDesc, shifts, dims), OUTPUT(yDesc)); | ||
| 64 | + uint64_t workspaceSize = 0; | ||
| 65 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspaceSize); | ||
| 66 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +TEST_F(test_aclnn_roll, case_invalid_dims_range) | ||
| 70 | +{ | ||
| 71 | + auto xDesc = TensorDesc({2, 3}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 72 | + auto yDesc = TensorDesc({2, 3}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 73 | + auto shifts = IntArrayDesc(std::vector<int64_t>{1}); | ||
| 74 | + auto dims = IntArrayDesc(std::vector<int64_t>{2}); | ||
| 75 | + | ||
| 76 | + auto ut = OP_API_UT(aclnnRoll, INPUT(xDesc, shifts, dims), OUTPUT(yDesc)); | ||
| 77 | + uint64_t workspaceSize = 0; | ||
| 78 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspaceSize); | ||
| 79 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 80 | +} | ||
| @@ -0,0 +1,35 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | +class RollInfershape : public testing::Test {}; | ||
| 16 | + | ||
| 17 | +TEST_F(RollInfershape, roll_infershape_basic) | ||
| 18 | +{ | ||
| 19 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 20 | + "Roll", | ||
| 21 | + { | ||
| 22 | + {{{2, 3, 4}, {2, 3, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 23 | + }, | ||
| 24 | + { | ||
| 25 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 26 | + }, | ||
| 27 | + { | ||
| 28 | + gert::InfershapeContextPara::OpAttr("shifts", Ops::Math::AnyValue::CreateFrom<std::vector<int64_t>>({1})), | ||
| 29 | + gert::InfershapeContextPara::OpAttr("dims", Ops::Math::AnyValue::CreateFrom<std::vector<int64_t>>({1})), | ||
| 30 | + }); | ||
| 31 | + std::vector<std::vector<int64_t>> expectOutputShape = { | ||
| 32 | + {2, 3, 4}, | ||
| 33 | + }; | ||
| 34 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape); | ||
| 35 | +} | ||
| @@ -0,0 +1,84 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace { | ||
| 17 | +struct RollCompileInfoForTest { | ||
| 18 | + int32_t coreNum = 64; | ||
| 19 | +}; | ||
| 20 | +} // namespace | ||
| 21 | + | ||
| 22 | +class RollTiling : public testing::Test {}; | ||
| 23 | + | ||
| 24 | +TEST_F(RollTiling, basic_last_dim_roll) | ||
| 25 | +{ | ||
| 26 | + RollCompileInfoForTest compileInfo = {64}; | ||
| 27 | + gert::TilingContextPara tilingContextPara( | ||
| 28 | + "Roll", | ||
| 29 | + { | ||
| 30 | + {{{2, 3}, {2, 3}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 31 | + }, | ||
| 32 | + { | ||
| 33 | + {{{2, 3}, {2, 3}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 34 | + }, | ||
| 35 | + { | ||
| 36 | + gert::TilingContextPara::OpAttr("shifts", Ops::Math::AnyValue::CreateFrom<std::vector<int64_t>>({1})), | ||
| 37 | + gert::TilingContextPara::OpAttr("dims", Ops::Math::AnyValue::CreateFrom<std::vector<int64_t>>({1})), | ||
| 38 | + }, | ||
| 39 | + &compileInfo); | ||
| 40 | + | ||
| 41 | + TilingInfo tilingInfo; | ||
| 42 | + ASSERT_TRUE(ExecuteTiling(tilingContextPara, tilingInfo)); | ||
| 43 | + ASSERT_EQ(tilingInfo.tilingKey, 0); | ||
| 44 | + ASSERT_GT(tilingInfo.blockNum, 0U); | ||
| 45 | + ASSERT_EQ(tilingInfo.workspaceSizes.size(), 1U); | ||
| 46 | + ASSERT_EQ(tilingInfo.workspaceSizes[0], 0); | ||
| 47 | + ASSERT_GE(tilingInfo.tilingDataSize, sizeof(RollTilingData)); | ||
| 48 | + | ||
| 49 | + auto* data = reinterpret_cast<const RollTilingData*>(tilingInfo.tilingData.get()); | ||
| 50 | + EXPECT_EQ(data->totalNum, 6); | ||
| 51 | + EXPECT_EQ(data->dimNum, 2); | ||
| 52 | + EXPECT_EQ(data->activeDimCount, 1); | ||
| 53 | + EXPECT_EQ(data->activeDim, 1); | ||
| 54 | + EXPECT_EQ(data->dimSize, 3); | ||
| 55 | + EXPECT_EQ(data->innerSize, 1); | ||
| 56 | + EXPECT_EQ(data->activeShift, 1); | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +TEST_F(RollTiling, flatten_roll_when_dims_empty) | ||
| 60 | +{ | ||
| 61 | + RollCompileInfoForTest compileInfo = {64}; | ||
| 62 | + gert::TilingContextPara tilingContextPara( | ||
| 63 | + "Roll", | ||
| 64 | + { | ||
| 65 | + {{{2, 3, 4}, {2, 3, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 66 | + }, | ||
| 67 | + { | ||
| 68 | + {{{2, 3, 4}, {2, 3, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 69 | + }, | ||
| 70 | + { | ||
| 71 | + gert::TilingContextPara::OpAttr("shifts", Ops::Math::AnyValue::CreateFrom<std::vector<int64_t>>({5})), | ||
| 72 | + gert::TilingContextPara::OpAttr("dims", Ops::Math::AnyValue::CreateFrom<std::vector<int64_t>>({})), | ||
| 73 | + }, | ||
| 74 | + &compileInfo); | ||
| 75 | + | ||
| 76 | + TilingInfo tilingInfo; | ||
| 77 | + ASSERT_TRUE(ExecuteTiling(tilingContextPara, tilingInfo)); | ||
| 78 | + auto* data = reinterpret_cast<const RollTilingData*>(tilingInfo.tilingData.get()); | ||
| 79 | + EXPECT_EQ(data->dimNum, 1); | ||
| 80 | + EXPECT_EQ(data->totalNum, 24); | ||
| 81 | + EXPECT_EQ(data->shapes[0], 24); | ||
| 82 | + EXPECT_EQ(data->strides[0], 1); | ||
| 83 | + EXPECT_EQ(data->shifts[0], 5); | ||
| 84 | +} | ||
| @@ -0,0 +1,17 @@ | |||
| 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 | +if (UT_TEST_ALL OR OP_KERNEL_UT) | ||
| 12 | + set(roll_tiling_files | ||
| 13 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../op_host/roll_tiling.cpp | ||
| 14 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../op_host/roll_infershape.cpp | ||
| 15 | + ) | ||
| 16 | + AddOpTestCase(roll "ascend910b" "-DDTYPE_X=float" "${roll_tiling_files}") | ||
| 17 | +endif() | ||
| @@ -0,0 +1,44 @@ | |||
| 1 | +/*! | ||
| 2 | + * \file roll_tiling.h | ||
| 3 | + * \brief Roll tiling data for kernel UT | ||
| 4 | + */ | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +inline void InitTilingData(uint8_t* tiling, RollTilingData* constData) | ||
| 32 | +{ | ||
| 33 | + memcpy(constData, tiling, sizeof(RollTilingData)); | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + tilingStruct tilingData; \ | ||
| 38 | + InitTilingData(tilingArg, &tilingData) | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + RollTilingData tilingData; \ | ||
| 42 | + InitTilingData(tilingArg, &tilingData) | ||
| 43 | + | ||
| 44 | + | ||
| @@ -0,0 +1,65 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +class RollKernelTest : public testing::Test {}; | ||
| 21 | + | ||
| 22 | +TEST_F(RollKernelTest, kernel_launch_smoke) | ||
| 23 | +{ | ||
| 24 | + constexpr size_t size = 6; | ||
| 25 | + constexpr uint32_t numBlocks = 1; | ||
| 26 | + | ||
| 27 | + std::vector<float> xHost = {0, 1, 2, 3, 4, 5}; | ||
| 28 | + std::vector<float> yHost(size, 0); | ||
| 29 | + | ||
| 30 | + uint8_t* x = (uint8_t*)AscendC::GmAlloc(size * sizeof(float)); | ||
| 31 | + uint8_t* y = (uint8_t*)AscendC::GmAlloc(size * sizeof(float)); | ||
| 32 | + uint8_t* workspace = (uint8_t*)AscendC::GmAlloc(32); | ||
| 33 | + uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(sizeof(RollTilingData)); | ||
| 34 | + | ||
| 35 | + memcpy(x, xHost.data(), size * sizeof(float)); | ||
| 36 | + memcpy(y, yHost.data(), size * sizeof(float)); | ||
| 37 | + | ||
| 38 | + auto* tilingData = reinterpret_cast<RollTilingData*>(tiling); | ||
| 39 | + memset(tilingData, 0, sizeof(RollTilingData)); | ||
| 40 | + tilingData->totalNum = size; | ||
| 41 | + tilingData->dimNum = 1; | ||
| 42 | + tilingData->perCoreElements = size; | ||
| 43 | + tilingData->lastCoreElements = size; | ||
| 44 | + tilingData->usedCoreNum = 1; | ||
| 45 | + tilingData->ubElements = size; | ||
| 46 | + tilingData->blockFactor = size; | ||
| 47 | + tilingData->ubFactor = size; | ||
| 48 | + tilingData->activeDimCount = 1; | ||
| 49 | + tilingData->activeDim = 0; | ||
| 50 | + tilingData->dimSize = size; | ||
| 51 | + tilingData->innerSize = 1; | ||
| 52 | + tilingData->activeShift = 1; | ||
| 53 | + tilingData->shapes[0] = size; | ||
| 54 | + tilingData->strides[0] = 1; | ||
| 55 | + tilingData->shifts[0] = 1; | ||
| 56 | + | ||
| 57 | + ICPU_SET_TILING_KEY(0); | ||
| 58 | + AscendC::SetKernelMode(KernelMode::AIV_MODE); | ||
| 59 | + ICPU_RUN_KF((roll<0>), numBlocks, x, y, workspace, tiling); | ||
| 60 | + | ||
| 61 | + AscendC::GmFree(x); | ||
| 62 | + AscendC::GmFree(y); | ||
| 63 | + AscendC::GmFree(workspace); | ||
| 64 | + AscendC::GmFree(tiling); | ||
| 65 | +} | ||