已合并
【feat】: 新增ascir:Rand/Randn #1749
liyuewei创建于 8月15日
【feat】: 新增ascir:Rand/Randn #1749
已合并
共 26 个文件变更+881-2
| @@ -371,6 +371,8 @@ inline const std::string kRoundToInt = "RoundToInt"; | |||
| 371 | inline const std::string kTruncToInt = "TruncToInt"; | 371 | inline const std::string kTruncToInt = "TruncToInt"; |
| 372 | inline const std::string kTrunc = "Trunc"; | 372 | inline const std::string kTrunc = "Trunc"; |
| 373 | inline const std::string kVmAdd = "VmAdd"; | 373 | inline const std::string kVmAdd = "VmAdd"; |
| 374 | +inline const std::string kRand = "Rand"; | ||
| 375 | +inline const std::string kRandn = "Randn"; | ||
| 374 | inline const std::string kPlaceholder = "Placeholder"; | 376 | inline const std::string kPlaceholder = "Placeholder"; |
| 375 | 377 | ||
| 376 | 378 | ||
| @@ -104,6 +104,8 @@ static const std::map<std::string, af::ComputeType> kOpTypeToComputeType = { | |||
| 104 | {Scalar::Type, af::ComputeType::kComputeInvalid}, | 104 | {Scalar::Type, af::ComputeType::kComputeInvalid}, |
| 105 | {Output::Type, af::ComputeType::kComputeInvalid}, | 105 | {Output::Type, af::ComputeType::kComputeInvalid}, |
| 106 | {IndexExpr::Type, af::ComputeType::kComputeInvalid}, | 106 | {IndexExpr::Type, af::ComputeType::kComputeInvalid}, |
| 107 | + {"Rand", af::ComputeType::kComputeInvalid}, | ||
| 108 | + {"Randn", af::ComputeType::kComputeInvalid}, | ||
| 107 | 109 | ||
| 108 | {Load::Type, af::ComputeType::kComputeLoad}, | 110 | {Load::Type, af::ComputeType::kComputeLoad}, |
| 109 | {Store::Type, af::ComputeType::kComputeStore}, | 111 | {Store::Type, af::ComputeType::kComputeStore}, |
| @@ -146,6 +146,8 @@ PyMODINIT_FUNC PyInit_pyautofuse(void); | |||
| 146 | OP(Axpy) \ | 146 | OP(Axpy) \ |
| 147 | OP(CopySign) \ | 147 | OP(CopySign) \ |
| 148 | OP(Ceil2Int) \ | 148 | OP(Ceil2Int) \ |
| 149 | + OP(Rand) \ | ||
| 150 | + OP(Randn) \ | ||
| 149 | OP(RoundToInt) \ | 151 | OP(RoundToInt) \ |
| 150 | OP(Square) \ | 152 | OP(Square) \ |
| 151 | OP(Sinh) \ | 153 | OP(Sinh) \ |
| @@ -2272,3 +2272,55 @@ def I1e( | |||
| 2272 | return _common_in_1_out_1_normal_op( | 2272 | return _common_in_1_out_1_normal_op( |
| 2273 | "I1e", owner_graph, x, axis=axis, size=size, stride=stride | 2273 | "I1e", owner_graph, x, axis=axis, size=size, stride=stride |
| 2274 | ) | 2274 | ) |
| 2275 | + | ||
| 2276 | + | ||
| 2277 | +def Rand( | ||
| 2278 | + owner_graph: ascir.HintGraph, | ||
| 2279 | + *, | ||
| 2280 | + dtype: ascir.dtypes, | ||
| 2281 | + axis: List[ascir.Axis], | ||
| 2282 | + size: Optional[List[ascir.SizeExpr]] = None, | ||
| 2283 | + stride: Optional[List[ascir.SizeExpr]] = None, | ||
| 2284 | +) -> ascir.OpsOperatorOutput: | ||
| 2285 | + """ | ||
| 2286 | + Rand - generate uniform random numbers using PhiloxRandom algorithm. | ||
| 2287 | + Uses fixed philoxKey = {0, 0} and philoxCounter = {0, 0, 0, 0} for continuous mode. | ||
| 2288 | + Supports float data type. | ||
| 2289 | + """ | ||
| 2290 | + meta = _get_metadata(owner_graph) | ||
| 2291 | + name = _generate_op_name(owner_graph, "rand") | ||
| 2292 | + rand_op = ascir.ops.Rand(name, owner_graph) | ||
| 2293 | + meta.ops.append(rand_op) | ||
| 2294 | + | ||
| 2295 | + # Set dtype and view, then infer | ||
| 2296 | + rand_op.y.dtype = dtype | ||
| 2297 | + _infer_or_set_view(rand_op.y, axis, size, stride) | ||
| 2298 | + rand_op.infer_dtype() | ||
| 2299 | + | ||
| 2300 | + return rand_op.y | ||
| 2301 | + | ||
| 2302 | + | ||
| 2303 | +def Randn( | ||
| 2304 | + owner_graph: ascir.HintGraph, | ||
| 2305 | + *, | ||
| 2306 | + dtype: ascir.dtypes, | ||
| 2307 | + axis: List[ascir.Axis], | ||
| 2308 | + size: Optional[List[ascir.SizeExpr]] = None, | ||
| 2309 | + stride: Optional[List[ascir.SizeExpr]] = None, | ||
| 2310 | +) -> ascir.OpsOperatorOutput: | ||
| 2311 | + """ | ||
| 2312 | + Randn - generate normal random numbers using PhiloxRandom algorithm. | ||
| 2313 | + Uses fixed philoxKey = {0, 0} and philoxCounter = {0, 0, 0, 0} for continuous mode. | ||
| 2314 | + Supports uint32_t and int32_t data types. | ||
| 2315 | + """ | ||
| 2316 | + meta = _get_metadata(owner_graph) | ||
| 2317 | + name = _generate_op_name(owner_graph, "randn") | ||
| 2318 | + randn_op = ascir.ops.Randn(name, owner_graph) | ||
| 2319 | + meta.ops.append(randn_op) | ||
| 2320 | + | ||
| 2321 | + # Set dtype and view, then infer | ||
| 2322 | + randn_op.y.dtype = dtype | ||
| 2323 | + _infer_or_set_view(randn_op.y, axis, size, stride) | ||
| 2324 | + randn_op.infer_dtype() | ||
| 2325 | + | ||
| 2326 | + return randn_op.y | ||
| @@ -371,7 +371,9 @@ af::Status BaseAlignmentStrategy::AlignVectorizedStrides(ascir::ImplGraph &impl_ | |||
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | af::Status BaseAlignmentStrategy::InferAlignmentForOneNode(ascir::ImplGraph &, const af::AscNodePtr &node, bool &) { | 373 | af::Status BaseAlignmentStrategy::InferAlignmentForOneNode(ascir::ImplGraph &, const af::AscNodePtr &node, bool &) { |
| 374 | - GE_ASSERT_TRUE(!node->inputs().empty(), "The inputs of %s(%s) is empty.", node->GetTypePtr(), node->GetNamePtr()); | 374 | + GE_ASSERT_TRUE( |
| 375 | + !node->inputs().empty() || af::ops::IsOps<af::ascir_op::Rand>(node) || af::ops::IsOps<af::ascir_op::Randn>(node), | ||
| 376 | + "The inputs of %s(%s) is empty.", node->GetTypePtr(), node->GetNamePtr()); | ||
| 375 | GE_ASSERT_TRUE(!node->outputs().empty(), "The output of %s(%s) is empty.", node->GetTypePtr(), node->GetNamePtr()); | 377 | GE_ASSERT_TRUE(!node->outputs().empty(), "The output of %s(%s) is empty.", node->GetTypePtr(), node->GetNamePtr()); |
| 376 | af::ComputeType compute_type = node->attr.api.compute_type; | 378 | af::ComputeType compute_type = node->attr.api.compute_type; |
| 377 | auto it = compute_type_to_infer_func_.find(compute_type); | 379 | auto it = compute_type_to_infer_func_.find(compute_type); |
| @@ -34,6 +34,9 @@ target_include_directories(test_codegen PRIVATE | |||
| 34 | ${CODE_ROOT_DIR}/v35/codegen/micro_api_call | 34 | ${CODE_ROOT_DIR}/v35/codegen/micro_api_call |
| 35 | ${CODE_ROOT_DIR}/v35/codegen/reg_api_call | 35 | ${CODE_ROOT_DIR}/v35/codegen/reg_api_call |
| 36 | ${CODE_ROOT_DIR}/v35/codegen/vec_func_call | 36 | ${CODE_ROOT_DIR}/v35/codegen/vec_func_call |
| 37 | + ${CODE_ROOT_DIR} | ||
| 38 | + ${CODE_ROOT_DIR}/ascir | ||
| 39 | + ${CODE_ROOT_DIR}/v35/ascir | ||
| 37 | ) | 40 | ) |
| 38 | 41 | ||
| 39 | target_sources(test_codegen PRIVATE | 42 | target_sources(test_codegen PRIVATE |
| @@ -215,3 +215,5 @@ add_subdirectory(expm_test) | |||
| 215 | add_subdirectory(round_to_int_float_to_int32_test) | 215 | add_subdirectory(round_to_int_float_to_int32_test) |
| 216 | add_subdirectory(trunc_to_int_bf16_to_int32_test) | 216 | add_subdirectory(trunc_to_int_bf16_to_int32_test) |
| 217 | # add_subdirectory(remainder_bf16_test) | 217 | # add_subdirectory(remainder_bf16_test) |
| 218 | +add_subdirectory(rand_store_test) | ||
| 219 | +add_subdirectory(randn_store_test) | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +backend_e2e_st_test(rand_store_test | ||
| 2 | + CODEGEN rand_store_backend_generator.cpp | ||
| 3 | + KERNEL_SRC | ||
| 4 | + rand_store_test_kernel.cpp | ||
| 5 | + rand_store_test_tiling.cpp | ||
| 6 | + autofuse_tiling_data.h | ||
| 7 | + TEST_SRC test_e2e_rand_store_kernel.cpp) | ||
| 8 | +target_include_directories(rand_store_test_e2e_v2 PRIVATE ${CODE_ROOT_DIR}/v35/ascendc/api_regbase) | ||
| @@ -0,0 +1,79 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under | ||
| 4 | + * the terms and conditions of CANN Open Software License Agreement Version 2.0 | ||
| 5 | + * (the "License"). Please refer to the License for details. You may not use | ||
| 6 | + * this file except in compliance with the License. THIS SOFTWARE IS PROVIDED ON | ||
| 7 | + * AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS | ||
| 9 | + * FOR A PARTICULAR PURPOSE. See LICENSE in the root of the software repository | ||
| 10 | + * for the full text of the License. | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +class TestBackendRandStoreE2e : public testing::Test { | ||
| 29 | + protected: | ||
| 30 | + void SetUp() override { | ||
| 31 | + dlog_setlevel(ASCGEN_MODULE_NAME, DLOG_ERROR, 0); | ||
| 32 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 33 | + auto rand_stub_v2 = std::make_shared<af::RuntimeStubV2>(); | ||
| 34 | + ge::RuntimeStub::SetInstance(rand_stub_v2); | ||
| 35 | + } | ||
| 36 | + void TearDown() override { | ||
| 37 | + dlog_setlevel(ASCGEN_MODULE_NAME, DLOG_ERROR, 0); | ||
| 38 | + ge::RuntimeStub::Reset(); | ||
| 39 | + } | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +TEST_F(TestBackendRandStoreE2e, RandStoreE2eCodegen) { | ||
| 43 | + bool gen_success = true; | ||
| 44 | + std::string rand_tiling_stub = R"( | ||
| 45 | + | ||
| 46 | + | ||
| 47 | +)"; | ||
| 48 | + | ||
| 49 | + std::map<std::string, std::string> rand_shape_info({{"s0", "stub_s0"}}); | ||
| 50 | + auto graph = ascir::ShareGraph::RandStoreFusedGraph(1); | ||
| 51 | + std::vector<std::string> rand_parts = splitString(KERNEL_SRC_LIST, ':'); | ||
| 52 | + const std::string &kernel_src_file_name = rand_parts[0]; | ||
| 53 | + const std::string &tiling_src_file_name = rand_parts[1]; | ||
| 54 | + const std::string &tiling_data_src_file_name = rand_parts[2]; | ||
| 55 | + | ||
| 56 | + try { | ||
| 57 | + optimize::Optimizer rand_optimizer(optimize::OptimizerOptions{}); | ||
| 58 | + codegen::Codegen rand_codegen(codegen::CodegenOptions{}); | ||
| 59 | + | ||
| 60 | + std::fstream rand_kernel_stream(kernel_src_file_name, std::ios::out); | ||
| 61 | + std::fstream rand_tiling_stream(tiling_src_file_name, std::ios::out); | ||
| 62 | + std::fstream rand_data_stream(tiling_data_src_file_name, std::ios::out); | ||
| 63 | + | ||
| 64 | + std::vector<::ascir::ScheduledResult> rand_schedules; | ||
| 65 | + ascir::FusedScheduledResult rand_fused_result; | ||
| 66 | + rand_fused_result.node_idx_to_scheduled_results.push_back(rand_schedules); | ||
| 67 | + EXPECT_EQ(rand_optimizer.Optimize(graph, rand_fused_result), 0); | ||
| 68 | + codegen::CodegenResult rand_result; | ||
| 69 | + EXPECT_EQ(rand_codegen.Generate(rand_shape_info, rand_fused_result, rand_result), 0); | ||
| 70 | + EXPECT_NE(rand_result.kernel.find("Rand("), std::string::npos); | ||
| 71 | + rand_kernel_stream << rand_tiling_stub << RemoveSubDirInclude(rand_result.kernel); | ||
| 72 | + rand_tiling_stream << rand_result.tiling; | ||
| 73 | + rand_data_stream << rand_result.tiling_data; | ||
| 74 | + } catch (...) { | ||
| 75 | + gen_success = false; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + EXPECT_EQ(gen_success, true); | ||
| 79 | +} | ||
| @@ -0,0 +1,60 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under | ||
| 4 | + * the terms and conditions of CANN Open Software License Agreement Version 2.0 | ||
| 5 | + * (the "License"). Please refer to the License for details. You may not use | ||
| 6 | + * this file except in compliance with the License. THIS SOFTWARE IS PROVIDED ON | ||
| 7 | + * AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS | ||
| 9 | + * FOR A PARTICULAR PURPOSE. See LICENSE in the root of the software repository | ||
| 10 | + * for the full text of the License. | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +extern "C" __global__ __aicore__ void rand_store_test(GM_ADDR y1, GM_ADDR workspace, GM_ADDR tiling); | ||
| 20 | +extern "C" int64_t AutofuseTiling(uint32_t s0, AutofuseTilingData *tiling, uint32_t *workspaceSize, uint64_t *blockDim, | ||
| 21 | + uint32_t aiv_num, uint32_t ub_size); | ||
| 22 | + | ||
| 23 | +class E2EBackendRandStoreCode : public testing::Test, public testing::WithParamInterface<int> {}; | ||
| 24 | + | ||
| 25 | +TEST_P(E2EBackendRandStoreCode, GenerateRandomNumbers) { | ||
| 26 | + auto test_size = GetParam(); | ||
| 27 | + uint64_t block_dim = 48; | ||
| 28 | + | ||
| 29 | + AutofuseTilingData tiling_data; | ||
| 30 | + float *y = static_cast<float *>(AscendC::GmAlloc(test_size * sizeof(float) + 32)); | ||
| 31 | + | ||
| 32 | + uint32_t ws_size = 0; | ||
| 33 | + AutofuseTiling(test_size, &tiling_data, &ws_size, &block_dim, 48, 192 * 1024); | ||
| 34 | + | ||
| 35 | + AscendC::SetKernelMode(KernelMode::AIV_MODE); | ||
| 36 | + ICPU_RUN_KF(rand_store_test, tiling_data.block_dim, reinterpret_cast<uint8_t *>(y), nullptr, | ||
| 37 | + reinterpret_cast<uint8_t *>(&tiling_data)); | ||
| 38 | + | ||
| 39 | + // Verify generated random numbers are in valid range [0, 1) | ||
| 40 | + uint32_t invalid_count = 0; | ||
| 41 | + uint32_t zero_count = 0; | ||
| 42 | + for (int i = 0; i < test_size; i++) { | ||
| 43 | + if (y[i] < 0.0F || y[i] >= 1.0F) { | ||
| 44 | + invalid_count++; | ||
| 45 | + } | ||
| 46 | + if (y[i] == 0.0F) { | ||
| 47 | + zero_count++; | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + // All values should be in [0, 1) | ||
| 52 | + EXPECT_EQ(invalid_count, 0U) << "Generated values outside [0, 1) range"; | ||
| 53 | + | ||
| 54 | + // Since it's random, we expect some non-zero values (extremely unlikely all are zero) | ||
| 55 | + EXPECT_LT(zero_count, test_size) << "All generated values are zero (unlikely for random generator)"; | ||
| 56 | + | ||
| 57 | + AscendC::GmFree(y); | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +INSTANTIATE_TEST_SUITE_P(GenerateWithDifferentSize, E2EBackendRandStoreCode, ::testing::Values(32, 64, 128, 256, 512)); | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +backend_e2e_st_test(randn_store_test | ||
| 2 | + CODEGEN randn_store_backend_generator.cpp | ||
| 3 | + KERNEL_SRC | ||
| 4 | + randn_store_test_kernel.cpp | ||
| 5 | + randn_store_test_tiling.cpp | ||
| 6 | + autofuse_tiling_data.h | ||
| 7 | + TEST_SRC test_e2e_randn_store_kernel.cpp) | ||
| 8 | +target_include_directories(randn_store_test_e2e_v2 PRIVATE ${CODE_ROOT_DIR}/v35/ascendc/api_regbase) | ||
| @@ -0,0 +1,79 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under | ||
| 4 | + * the terms and conditions of CANN Open Software License Agreement Version 2.0 | ||
| 5 | + * (the "License"). Please refer to the License for details. You may not use | ||
| 6 | + * this file except in compliance with the License. THIS SOFTWARE IS PROVIDED ON | ||
| 7 | + * AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS | ||
| 9 | + * FOR A PARTICULAR PURPOSE. See LICENSE in the root of the software repository | ||
| 10 | + * for the full text of the License. | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +class TestBackendRandnStoreE2e : public testing::Test { | ||
| 29 | + protected: | ||
| 30 | + void SetUp() override { | ||
| 31 | + dlog_setlevel(ASCGEN_MODULE_NAME, DLOG_ERROR, 0); | ||
| 32 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 33 | + auto randn_stub_v2 = std::make_shared<af::RuntimeStubV2>(); | ||
| 34 | + ge::RuntimeStub::SetInstance(randn_stub_v2); | ||
| 35 | + } | ||
| 36 | + void TearDown() override { | ||
| 37 | + dlog_setlevel(ASCGEN_MODULE_NAME, DLOG_ERROR, 0); | ||
| 38 | + ge::RuntimeStub::Reset(); | ||
| 39 | + } | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +TEST_F(TestBackendRandnStoreE2e, RandnStoreE2eCodegen) { | ||
| 43 | + bool gen_success = true; | ||
| 44 | + std::string randn_tiling_stub = R"( | ||
| 45 | + | ||
| 46 | + | ||
| 47 | +)"; | ||
| 48 | + | ||
| 49 | + std::map<std::string, std::string> randn_shape_info({{"s0", "stub_s0"}}); | ||
| 50 | + auto graph = ascir::ShareGraph::RandnStoreFusedGraph(1); | ||
| 51 | + std::vector<std::string> randn_parts = splitString(KERNEL_SRC_LIST, ':'); | ||
| 52 | + const std::string &kernel_src_file_name = randn_parts[0]; | ||
| 53 | + const std::string &tiling_src_file_name = randn_parts[1]; | ||
| 54 | + const std::string &tiling_data_src_file_name = randn_parts[2]; | ||
| 55 | + | ||
| 56 | + try { | ||
| 57 | + optimize::Optimizer randn_optimizer(optimize::OptimizerOptions{}); | ||
| 58 | + codegen::Codegen randn_codegen(codegen::CodegenOptions{}); | ||
| 59 | + | ||
| 60 | + std::fstream randn_kernel_stream(kernel_src_file_name, std::ios::out); | ||
| 61 | + std::fstream randn_tiling_stream(tiling_src_file_name, std::ios::out); | ||
| 62 | + std::fstream randn_data_stream(tiling_data_src_file_name, std::ios::out); | ||
| 63 | + | ||
| 64 | + std::vector<::ascir::ScheduledResult> randn_schedules; | ||
| 65 | + ascir::FusedScheduledResult randn_fused_result; | ||
| 66 | + randn_fused_result.node_idx_to_scheduled_results.push_back(randn_schedules); | ||
| 67 | + EXPECT_EQ(randn_optimizer.Optimize(graph, randn_fused_result), 0); | ||
| 68 | + codegen::CodegenResult randn_result; | ||
| 69 | + EXPECT_EQ(randn_codegen.Generate(randn_shape_info, randn_fused_result, randn_result), 0); | ||
| 70 | + EXPECT_NE(randn_result.kernel.find("Rand("), std::string::npos); | ||
| 71 | + randn_kernel_stream << randn_tiling_stub << RemoveSubDirInclude(randn_result.kernel); | ||
| 72 | + randn_tiling_stream << randn_result.tiling; | ||
| 73 | + randn_data_stream << randn_result.tiling_data; | ||
| 74 | + } catch (...) { | ||
| 75 | + gen_success = false; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + EXPECT_EQ(gen_success, true); | ||
| 79 | +} | ||
| @@ -0,0 +1,54 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under | ||
| 4 | + * the terms and conditions of CANN Open Software License Agreement Version 2.0 | ||
| 5 | + * (the "License"). Please refer to the License for details. You may not use | ||
| 6 | + * this file except in compliance with the License. THIS SOFTWARE IS PROVIDED ON | ||
| 7 | + * AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS | ||
| 9 | + * FOR A PARTICULAR PURPOSE. See LICENSE in the root of the software repository | ||
| 10 | + * for the full text of the License. | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +extern "C" __global__ __aicore__ void randn_store_test(GM_ADDR y1, GM_ADDR workspace, GM_ADDR tiling); | ||
| 20 | +extern "C" int64_t AutofuseTiling(uint32_t s0, AutofuseTilingData *tiling, uint32_t *workspaceSize, uint64_t *blockDim, | ||
| 21 | + uint32_t aiv_num, uint32_t ub_size); | ||
| 22 | + | ||
| 23 | +class E2EBackendRandnStoreCode : public testing::Test, public testing::WithParamInterface<int> {}; | ||
| 24 | + | ||
| 25 | +TEST_P(E2EBackendRandnStoreCode, GenerateRandomIntegers) { | ||
| 26 | + auto test_size = GetParam(); | ||
| 27 | + uint64_t block_dim = 48; | ||
| 28 | + | ||
| 29 | + AutofuseTilingData tiling_data; | ||
| 30 | + uint32_t *y = static_cast<uint32_t *>(AscendC::GmAlloc(test_size * sizeof(uint32_t) + 32)); | ||
| 31 | + | ||
| 32 | + uint32_t ws_size = 0; | ||
| 33 | + AutofuseTiling(test_size, &tiling_data, &ws_size, &block_dim, 48, 192 * 1024); | ||
| 34 | + | ||
| 35 | + AscendC::SetKernelMode(KernelMode::AIV_MODE); | ||
| 36 | + ICPU_RUN_KF(randn_store_test, tiling_data.block_dim, reinterpret_cast<uint8_t *>(y), nullptr, | ||
| 37 | + reinterpret_cast<uint8_t *>(&tiling_data)); | ||
| 38 | + | ||
| 39 | + // Verify generated random integers are in valid uint32_t range | ||
| 40 | + uint32_t zero_count = 0; | ||
| 41 | + for (int i = 0; i < test_size; i++) { | ||
| 42 | + // All values should be valid uint32_t (automatically true by type) | ||
| 43 | + if (y[i] == 0U) { | ||
| 44 | + zero_count++; | ||
| 45 | + } | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + // Since it's random, we expect some non-zero values (extremely unlikely all are zero) | ||
| 49 | + EXPECT_LT(zero_count, test_size) << "All generated values are zero (unlikely for random generator)"; | ||
| 50 | + | ||
| 51 | + AscendC::GmFree(y); | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +INSTANTIATE_TEST_SUITE_P(GenerateWithDifferentSize, E2EBackendRandnStoreCode, ::testing::Values(32, 64, 128, 256, 512)); | ||
| @@ -0,0 +1,249 @@ | |||
| 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 | + | ||
| 21 | + | ||
| 22 | +using namespace ge; | ||
| 23 | +using namespace af::ops; | ||
| 24 | +using namespace af::ascir_op; | ||
| 25 | + | ||
| 26 | +namespace codegen { | ||
| 27 | +namespace { | ||
| 28 | + | ||
| 29 | +// 创建 Rand 算子的测试图 | ||
| 30 | +void BuildRandGraph(af::AscGraph &graph, const af::Expression &s0, const af::Axis &z0, ge::DataType dtype) { | ||
| 31 | + Rand rand_op("Rand"); | ||
| 32 | + graph.AddNode(rand_op); | ||
| 33 | + | ||
| 34 | + *rand_op.y.axis = {z0.id}; | ||
| 35 | + *rand_op.y.repeats = {s0}; | ||
| 36 | + *rand_op.y.strides = {One}; | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +void InitRandAttrs(af::AscGraph &graph, ge::DataType dtype, const af::Axis &z0) { | ||
| 40 | + auto rand = graph.FindNode("Rand"); | ||
| 41 | + rand->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 42 | + rand->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 43 | + rand->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 44 | + rand->attr.sched.loop_axis = z0.id; | ||
| 45 | + | ||
| 46 | + auto &rand_attr = rand->outputs[0].attr; | ||
| 47 | + rand_attr.vectorized_axis = {z0.id}; | ||
| 48 | + rand_attr.vectorized_strides = {One}; | ||
| 49 | + rand_attr.dtype = dtype; | ||
| 50 | + rand_attr.mem.position = af::Position::kPositionVecOut; | ||
| 51 | + rand_attr.mem.tensor_id = 0; | ||
| 52 | + rand_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 53 | + rand_attr.que.id = 1; | ||
| 54 | + rand_attr.opt.merge_scope = af::kIdNone; | ||
| 55 | +} | ||
| 56 | + | ||
| 57 | +// 创建 Randn 算子的测试图 | ||
| 58 | +void BuildRandnGraph(af::AscGraph &graph, const af::Expression &s0, const af::Axis &z0, ge::DataType dtype) { | ||
| 59 | + Randn randn_op("Randn"); | ||
| 60 | + graph.AddNode(randn_op); | ||
| 61 | + | ||
| 62 | + *randn_op.y.axis = {z0.id}; | ||
| 63 | + *randn_op.y.repeats = {s0}; | ||
| 64 | + *randn_op.y.strides = {One}; | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +void InitRandnAttrs(af::AscGraph &graph, ge::DataType dtype, const af::Axis &z0) { | ||
| 68 | + auto randn = graph.FindNode("Randn"); | ||
| 69 | + randn->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 70 | + randn->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 71 | + randn->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 72 | + randn->attr.sched.loop_axis = z0.id; | ||
| 73 | + | ||
| 74 | + auto &randn_attr = randn->outputs[0].attr; | ||
| 75 | + randn_attr.vectorized_axis = {z0.id}; | ||
| 76 | + randn_attr.vectorized_strides = {One}; | ||
| 77 | + randn_attr.dtype = dtype; | ||
| 78 | + randn_attr.mem.position = af::Position::kPositionVecOut; | ||
| 79 | + randn_attr.mem.tensor_id = 0; | ||
| 80 | + randn_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 81 | + randn_attr.que.id = 1; | ||
| 82 | + randn_attr.opt.merge_scope = af::kIdNone; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +} // namespace | ||
| 86 | + | ||
| 87 | +// 测试 Rand Codegen 基本信息 | ||
| 88 | +TEST(CodegenKernel, TestRandCodegenBasicInfo) { | ||
| 89 | + af::AscGraph graph("test_rand_graph"); | ||
| 90 | + | ||
| 91 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 92 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 93 | + BuildRandGraph(graph, s0, z0, DT_FLOAT); | ||
| 94 | + InitRandAttrs(graph, DT_FLOAT, z0); | ||
| 95 | + | ||
| 96 | + auto rand = graph.FindNode("Rand"); | ||
| 97 | + | ||
| 98 | + // 创建 Codegen 实例并测试基本信息 | ||
| 99 | + af::ascir::RandAscIrCodegenImplV2 codegen; | ||
| 100 | + | ||
| 101 | + // 测试 GetApiName - Rand 返回 "Rand" | ||
| 102 | + std::string api_name = codegen.GetApiName(); | ||
| 103 | + EXPECT_EQ(api_name, "Rand"); | ||
| 104 | + | ||
| 105 | + // 测试 GetApiCallName | ||
| 106 | + std::string api_call_name = codegen.GetApiCallName(); | ||
| 107 | + EXPECT_EQ(api_call_name, "UnaryOutputApiCall"); | ||
| 108 | + | ||
| 109 | + // 测试 LoadApiHeaderFiles | ||
| 110 | + auto headers = codegen.LoadApiHeaderFiles(false); | ||
| 111 | + EXPECT_EQ(headers.size(), 1); | ||
| 112 | + EXPECT_EQ(headers[0], "random_reg_base.h"); | ||
| 113 | + | ||
| 114 | + // 测试 IncludeApiHeaderFiles(应该包含 AscendC Philox 头文件) | ||
| 115 | + auto include_headers = codegen.IncludeApiHeaderFiles(); | ||
| 116 | + EXPECT_EQ(include_headers.size(), 1); | ||
| 117 | + EXPECT_EQ(include_headers[0], "adv_api/math/philox.h"); | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +// 测试 Randn Codegen 基本信息 | ||
| 121 | +TEST(CodegenKernel, TestRandnCodegenBasicInfo) { | ||
| 122 | + af::AscGraph graph("test_randn_graph"); | ||
| 123 | + | ||
| 124 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 125 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 126 | + BuildRandnGraph(graph, s0, z0, DT_UINT32); | ||
| 127 | + InitRandnAttrs(graph, DT_UINT32, z0); | ||
| 128 | + | ||
| 129 | + auto randn = graph.FindNode("Randn"); | ||
| 130 | + | ||
| 131 | + // 创建 Codegen 实例并测试基本信息 | ||
| 132 | + af::ascir::RandnAscIrCodegenImplV2 codegen; | ||
| 133 | + | ||
| 134 | + // 测试 GetApiName - Randn 也返回 "Rand" | ||
| 135 | + std::string api_name = codegen.GetApiName(); | ||
| 136 | + EXPECT_EQ(api_name, "Rand"); | ||
| 137 | + | ||
| 138 | + // 测试 GetApiCallName | ||
| 139 | + std::string api_call_name = codegen.GetApiCallName(); | ||
| 140 | + EXPECT_EQ(api_call_name, "UnaryOutputApiCall"); | ||
| 141 | + | ||
| 142 | + // 测试 LoadApiHeaderFiles | ||
| 143 | + auto headers = codegen.LoadApiHeaderFiles(false); | ||
| 144 | + EXPECT_EQ(headers.size(), 1); | ||
| 145 | + EXPECT_EQ(headers[0], "random_reg_base.h"); | ||
| 146 | + | ||
| 147 | + // 测试 IncludeApiHeaderFiles(应该包含 AscendC Philox 头文件) | ||
| 148 | + auto include_headers = codegen.IncludeApiHeaderFiles(); | ||
| 149 | + EXPECT_EQ(include_headers.size(), 1); | ||
| 150 | + EXPECT_EQ(include_headers[0], "adv_api/math/philox.h"); | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +// 测试 Rand 不同 dtype 支持 | ||
| 154 | +TEST(CodegenKernel, TestRandDifferentDtypes) { | ||
| 155 | + std::vector<ge::DataType> supported_dtypes = {DT_FLOAT}; | ||
| 156 | + | ||
| 157 | + for (auto dtype : supported_dtypes) { | ||
| 158 | + af::AscGraph graph("test_rand_dtype_graph"); | ||
| 159 | + | ||
| 160 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 161 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 162 | + BuildRandGraph(graph, s0, z0, dtype); | ||
| 163 | + InitRandAttrs(graph, dtype, z0); | ||
| 164 | + | ||
| 165 | + auto rand = graph.FindNode("Rand"); | ||
| 166 | + EXPECT_EQ(rand->outputs[0].attr.dtype, dtype); | ||
| 167 | + } | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +// 测试 Randn 不同 dtype 支持 | ||
| 171 | +TEST(CodegenKernel, TestRandnDifferentDtypes) { | ||
| 172 | + std::vector<ge::DataType> supported_dtypes = {DT_UINT32, DT_INT32}; | ||
| 173 | + | ||
| 174 | + for (auto dtype : supported_dtypes) { | ||
| 175 | + af::AscGraph graph("test_randn_dtype_graph"); | ||
| 176 | + | ||
| 177 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 178 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 179 | + BuildRandnGraph(graph, s0, z0, dtype); | ||
| 180 | + InitRandnAttrs(graph, dtype, z0); | ||
| 181 | + | ||
| 182 | + auto randn = graph.FindNode("Randn"); | ||
| 183 | + EXPECT_EQ(randn->outputs[0].attr.dtype, dtype); | ||
| 184 | + } | ||
| 185 | +} | ||
| 186 | + | ||
| 187 | +// 测试 Rand 生成的 API 调用字符串(简化版) | ||
| 188 | +TEST(CodegenKernel, TestRandApiCallStringGeneration) { | ||
| 189 | + af::AscGraph graph("test_rand_api_call_graph"); | ||
| 190 | + | ||
| 191 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 192 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 193 | + BuildRandGraph(graph, s0, z0, DT_FLOAT); | ||
| 194 | + InitRandAttrs(graph, DT_FLOAT, z0); | ||
| 195 | + | ||
| 196 | + auto rand = graph.FindNode("Rand"); | ||
| 197 | + | ||
| 198 | + codegen::Tiler tiler; | ||
| 199 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 200 | + tpipe.AddTensor(rand->outputs[0]); | ||
| 201 | + | ||
| 202 | + tiler.AddAxis(z0); | ||
| 203 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 204 | + | ||
| 205 | + // 使用 UnaryOutputApiCall 来生成调用字符串 | ||
| 206 | + codegen::UnaryOutputApiCall call("Rand"); | ||
| 207 | + EXPECT_EQ(call.Init(rand), 0); | ||
| 208 | + | ||
| 209 | + std::string result; | ||
| 210 | + call.Generate(tpipe, {}, result); | ||
| 211 | + | ||
| 212 | + // 验证生成的字符串包含关键信息 | ||
| 213 | + EXPECT_NE(result.find("Rand"), std::string::npos); | ||
| 214 | + EXPECT_NE(result.find("local_0"), std::string::npos); | ||
| 215 | + EXPECT_NE(result.find("local_0_actual_size"), std::string::npos); | ||
| 216 | +} | ||
| 217 | + | ||
| 218 | +// 测试 Randn 生成的 API 调用字符串 | ||
| 219 | +TEST(CodegenKernel, TestRandnApiCallStringGeneration) { | ||
| 220 | + af::AscGraph graph("test_randn_api_call_graph"); | ||
| 221 | + | ||
| 222 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 223 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 224 | + BuildRandnGraph(graph, s0, z0, DT_UINT32); | ||
| 225 | + InitRandnAttrs(graph, DT_UINT32, z0); | ||
| 226 | + | ||
| 227 | + auto randn = graph.FindNode("Randn"); | ||
| 228 | + | ||
| 229 | + codegen::Tiler tiler; | ||
| 230 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 231 | + tpipe.AddTensor(randn->outputs[0]); | ||
| 232 | + | ||
| 233 | + tiler.AddAxis(z0); | ||
| 234 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 235 | + | ||
| 236 | + // 使用 UnaryOutputApiCall 来生成调用字符串 | ||
| 237 | + codegen::UnaryOutputApiCall call("Rand"); | ||
| 238 | + EXPECT_EQ(call.Init(randn), 0); | ||
| 239 | + | ||
| 240 | + std::string result; | ||
| 241 | + call.Generate(tpipe, {}, result); | ||
| 242 | + | ||
| 243 | + // 验证生成的字符串包含关键信息 | ||
| 244 | + EXPECT_NE(result.find("Rand"), std::string::npos); // Randn 也调用 Rand | ||
| 245 | + EXPECT_NE(result.find("local_0"), std::string::npos); | ||
| 246 | + EXPECT_NE(result.find("local_0_actual_size"), std::string::npos); | ||
| 247 | +} | ||
| 248 | + | ||
| 249 | +} // namespace codegen | ||
| @@ -15,6 +15,7 @@ set(ascendc_api_regbase_extend_src | |||
| 15 | floor_div.h | 15 | floor_div.h |
| 16 | pow.h | 16 | pow.h |
| 17 | polygamma.h | 17 | polygamma.h |
| 18 | + random.h | ||
| 18 | split.h | 19 | split.h |
| 19 | where.h | 20 | where.h |
| 20 | erf.h | 21 | erf.h |
| @@ -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 | + | ||
| 13 | +/** | ||
| 14 | + * @brief Rand - unified random number generation using AscendC PhiloxRandom API | ||
| 15 | + * Uses fixed philoxKey = {0, 0} and philoxCounter = {0, 0, 0, 0} for continuous mode | ||
| 16 | + * Supports float, float16, uint32_t, int32_t data types | ||
| 17 | + * | ||
| 18 | + * @tparam T data type, supports float, float16, uint32_t, int32_t | ||
| 19 | + * @param dst output tensor | ||
| 20 | + * @param size number of elements to generate | ||
| 21 | + */ | ||
| 22 | +template <typename T> | ||
| 23 | +inline __aicore__ void Rand(const AscendC::LocalTensor<T> &dst, const uint32_t size) { | ||
| 24 | + // PhiloxKey and PhiloxCounter are plain C arrays: uint32_t[2] and uint32_t[4] | ||
| 25 | + AscendC::PhiloxKey philoxKey = {0, 0}; | ||
| 26 | + AscendC::PhiloxCounter philoxCounter = {0, 0, 0, 0}; | ||
| 27 | + | ||
| 28 | + AscendC::PhiloxRandom<10>(dst, philoxKey, philoxCounter, size); | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | + | ||
| @@ -501,6 +501,16 @@ REG_ASC_IR(Output).Impl(v2_soc_versions, | |||
| 501 | {{"T", TensorType{DT_INT8, DT_UINT8, DT_INT16, DT_UINT16, DT_INT32, DT_UINT32, DT_INT64, | 501 | {{"T", TensorType{DT_INT8, DT_UINT8, DT_INT16, DT_UINT16, DT_INT32, DT_UINT32, DT_INT64, |
| 502 | DT_UINT64, DT_FLOAT16, DT_FLOAT, DT_BF16, DT_BOOL}}}}); | 502 | DT_UINT64, DT_FLOAT16, DT_FLOAT, DT_BF16, DT_BOOL}}}}); |
| 503 | 503 | ||
| 504 | +REG_ASC_IR(Rand).Inputs({}).Output("y", "T").StartNode().Impl( | ||
| 505 | + v2_soc_versions, {af::ascir::AscIrImplCreator<af::ascir::RandAscIrAttImplV2>(), | ||
| 506 | + af::ascir::AscIrImplCreator<af::ascir::RandAscIrCodegenImplV2>(), | ||
| 507 | + {{"T", TensorType{DT_FLOAT}}}}); | ||
| 508 | + | ||
| 509 | +REG_ASC_IR(Randn).Inputs({}).Output("y", "T").StartNode().Impl( | ||
| 510 | + v2_soc_versions, {af::ascir::AscIrImplCreator<af::ascir::RandnAscIrAttImplV2>(), | ||
| 511 | + af::ascir::AscIrImplCreator<af::ascir::RandnAscIrCodegenImplV2>(), | ||
| 512 | + {{"T", TensorType{DT_UINT32, DT_INT32}}}}); | ||
| 513 | + | ||
| 504 | REG_ASC_IR(Workspace).Impl(v2_soc_versions, | 514 | REG_ASC_IR(Workspace).Impl(v2_soc_versions, |
| 505 | {af::ascir::AscIrImplCreator<af::ascir::WorkspaceAscIrAttImplV2>(), | 515 | {af::ascir::AscIrImplCreator<af::ascir::WorkspaceAscIrAttImplV2>(), |
| 506 | af::ascir::AscIrImplCreator<af::ascir::WorkspaceAscIrCodegenImplV2>(), | 516 | af::ascir::AscIrImplCreator<af::ascir::WorkspaceAscIrCodegenImplV2>(), |
| @@ -199,6 +199,8 @@ REG_ASC_IR_ATT_V2_CLASS_DEFINE(LegendrePolynomialP); | |||
| 199 | REG_ASC_IR_ATT_V2_CLASS_DEFINE(AiryAi); | 199 | REG_ASC_IR_ATT_V2_CLASS_DEFINE(AiryAi); |
| 200 | REG_ASC_IR_ATT_V2_CLASS_DEFINE(Erfinv); | 200 | REG_ASC_IR_ATT_V2_CLASS_DEFINE(Erfinv); |
| 201 | REG_ASC_IR_ATT_V2_CLASS_DEFINE(Softmax); | 201 | REG_ASC_IR_ATT_V2_CLASS_DEFINE(Softmax); |
| 202 | +REG_ASC_IR_ATT_V2_CLASS_DEFINE(Rand); | ||
| 203 | +REG_ASC_IR_ATT_V2_CLASS_DEFINE(Randn); | ||
| 202 | } // namespace ascir | 204 | } // namespace ascir |
| 203 | } // namespace af | 205 | } // namespace af |
| 204 | 206 | ||
| @@ -5300,6 +5300,40 @@ class SoftmaxAscIrCodegenImplV2 : public AscIrCodegenV2 { | |||
| 5300 | } | 5300 | } |
| 5301 | }; | 5301 | }; |
| 5302 | 5302 | ||
| 5303 | +/*********************************************************************************/ | ||
| 5304 | +class RandAscIrCodegenImplV2 : public AscIrCodegenV2 { | ||
| 5305 | + public: | ||
| 5306 | + [[nodiscard]] std::string GetApiCallName() const override { | ||
| 5307 | + return "UnaryOutputApiCall"; | ||
| 5308 | + } | ||
| 5309 | + [[nodiscard]] std::string GetApiName() const override { | ||
| 5310 | + return "Rand"; | ||
| 5311 | + } | ||
| 5312 | + [[nodiscard]] std::vector<std::string> LoadApiHeaderFiles([[maybe_unused]] bool is_dynamic) const override { | ||
| 5313 | + return {"random_reg_base.h"}; | ||
| 5314 | + } | ||
| 5315 | + [[nodiscard]] std::vector<std::string> IncludeApiHeaderFiles() const override { | ||
| 5316 | + return {"adv_api/math/philox.h"}; | ||
| 5317 | + } | ||
| 5318 | +}; | ||
| 5319 | + | ||
| 5320 | +/*********************************************************************************/ | ||
| 5321 | +class RandnAscIrCodegenImplV2 : public AscIrCodegenV2 { | ||
| 5322 | + public: | ||
| 5323 | + [[nodiscard]] std::string GetApiCallName() const override { | ||
| 5324 | + return "UnaryOutputApiCall"; | ||
| 5325 | + } | ||
| 5326 | + [[nodiscard]] std::string GetApiName() const override { | ||
| 5327 | + return "Rand"; | ||
| 5328 | + } | ||
| 5329 | + [[nodiscard]] std::vector<std::string> LoadApiHeaderFiles([[maybe_unused]] bool is_dynamic) const override { | ||
| 5330 | + return {"random_reg_base.h"}; | ||
| 5331 | + } | ||
| 5332 | + [[nodiscard]] std::vector<std::string> IncludeApiHeaderFiles() const override { | ||
| 5333 | + return {"adv_api/math/philox.h"}; | ||
| 5334 | + } | ||
| 5335 | +}; | ||
| 5336 | + | ||
| 5303 | /*********************************************************************************/ | 5337 | /*********************************************************************************/ |
| 5304 | class UnsupportedAscIrCodegenImplV2 : public AscIrCodegenV2 { | 5338 | class UnsupportedAscIrCodegenImplV2 : public AscIrCodegenV2 { |
| 5305 | public: | 5339 | public: |
| @@ -914,6 +914,10 @@ ApiPerfRegister<ApiPerf> airy_ai_api_perf_v2(ApiPerfRegisterV2(kAiryAi, GetPerfF | |||
| 914 | &perf_param_table_v2, &tiling_schedule_config_table_v2)); | 914 | &perf_param_table_v2, &tiling_schedule_config_table_v2)); |
| 915 | ApiPerfRegister<ApiPerf> erfinv_api_perf_v2(ApiPerfRegisterV2(kErfinv, GetPerfFunc(kUnitVector), nullptr, | 915 | ApiPerfRegister<ApiPerf> erfinv_api_perf_v2(ApiPerfRegisterV2(kErfinv, GetPerfFunc(kUnitVector), nullptr, |
| 916 | &perf_param_table_v2, &tiling_schedule_config_table_v2)); | 916 | &perf_param_table_v2, &tiling_schedule_config_table_v2)); |
| 917 | +ApiPerfRegister<ApiPerf> rand_api_perf_v2(ApiPerfRegisterV2(kRand, GetPerfFunc(kUnitVector), nullptr, | ||
| 918 | + &perf_param_table_v2, &tiling_schedule_config_table_v2)); | ||
| 919 | +ApiPerfRegister<ApiPerf> randn_api_perf_v2(ApiPerfRegisterV2(kRandn, GetPerfFunc(kUnitVector), nullptr, | ||
| 920 | + &perf_param_table_v2, &tiling_schedule_config_table_v2)); | ||
| 917 | ApiPerfRegister<ApiPerf> square_api_perf_v2(ApiPerfRegisterV2(kSquare, GetPerfFunc(kSquare + "V2"), nullptr, | 921 | ApiPerfRegister<ApiPerf> square_api_perf_v2(ApiPerfRegisterV2(kSquare, GetPerfFunc(kSquare + "V2"), nullptr, |
| 918 | &perf_param_table_v2, &tiling_schedule_config_table_v2)); | 922 | &perf_param_table_v2, &tiling_schedule_config_table_v2)); |
| 919 | 923 | ||
| @@ -239,6 +239,9 @@ Register::Register() { | |||
| 239 | }; | 239 | }; |
| 240 | const std::string kAscendcPolyGammaRegBaseStr = { | 240 | const std::string kAscendcPolyGammaRegBaseStr = { |
| 241 | 241 | ||
| 242 | + }; | ||
| 243 | + const std::string kAscendcRandomRegBaseStr = { | ||
| 244 | + | ||
| 242 | }; | 245 | }; |
| 243 | const std::string kAscendcSignBitRegBaseStr = { | 246 | const std::string kAscendcSignBitRegBaseStr = { |
| 244 | 247 | ||
| @@ -363,6 +366,7 @@ Register::Register() { | |||
| 363 | {"log_ndtr_reg_base.h", kAscendcLogNdtrRegBaseStr}, | 366 | {"log_ndtr_reg_base.h", kAscendcLogNdtrRegBaseStr}, |
| 364 | {"next_after_reg_base.h", kAscendcNextAfterRegBaseStr}, | 367 | {"next_after_reg_base.h", kAscendcNextAfterRegBaseStr}, |
| 365 | {"polygamma_reg_base.h", kAscendcPolyGammaRegBaseStr}, | 368 | {"polygamma_reg_base.h", kAscendcPolyGammaRegBaseStr}, |
| 369 | + {"random_reg_base.h", kAscendcRandomRegBaseStr}, | ||
| 366 | {"signbit_reg_base.h", kAscendcSignBitRegBaseStr}, | 370 | {"signbit_reg_base.h", kAscendcSignBitRegBaseStr}, |
| 367 | {"frexp_reg_base.h", kAscendcFrexpRegBaseStr}, | 371 | {"frexp_reg_base.h", kAscendcFrexpRegBaseStr}, |
| 368 | {"shifted_chebyshev_polynomial_utils_reg_base.h", kAscendcShiftedChebyshevPolynomialUtilsRegBaseStr}, | 372 | {"shifted_chebyshev_polynomial_utils_reg_base.h", kAscendcShiftedChebyshevPolynomialUtilsRegBaseStr}, |
| @@ -0,0 +1,48 @@ | |||
| 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 | + | ||
| 21 | +namespace codegen { | ||
| 22 | +using namespace std; | ||
| 23 | +using namespace af::ops; | ||
| 24 | +using namespace af::ascir_op; | ||
| 25 | + | ||
| 26 | +Status UnaryOutputApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> ¤t_axis, | ||
| 27 | + const std::vector<std::reference_wrapper<const Tensor>> &inputs, | ||
| 28 | + const std::vector<std::reference_wrapper<const Tensor>> &outputs, | ||
| 29 | + std::string &result) const { | ||
| 30 | + // 验证:无输入,单输出 | ||
| 31 | + GE_CHK_BOOL_RET_STATUS(inputs.empty(), af::FAILED, "UnaryOutputApiCall expects no inputs, but got %zu inputs", | ||
| 32 | + inputs.size()); | ||
| 33 | + GE_CHK_BOOL_RET_STATUS(outputs.size() == 1, af::FAILED, | ||
| 34 | + "UnaryOutputApiCall expects exactly 1 output, but got %zu outputs", outputs.size()); | ||
| 35 | + | ||
| 36 | + auto y = outputs[0].get(); | ||
| 37 | + | ||
| 38 | + stringstream ss; | ||
| 39 | + // 生成 API 调用:Rand(local_0[0], local_0_actual_size); | ||
| 40 | + ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " | ||
| 41 | + << y.actual_size << ");" << std::endl; | ||
| 42 | + | ||
| 43 | + result = ss.str(); | ||
| 44 | + return af::SUCCESS; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +static ApiCallRegister<UnaryOutputApiCall> register_unary_output_api_call("UnaryOutputApiCall"); | ||
| 48 | +} // namespace codegen | ||
| @@ -0,0 +1,34 @@ | |||
| 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 | +namespace codegen { | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * @brief UnaryOutputApiCall - API call generator for operators with no inputs and single output | ||
| 19 | + * Specifically designed for operators like Rand that generate data without input tensors | ||
| 20 | + */ | ||
| 21 | +class UnaryOutputApiCall final : public ApiCall { | ||
| 22 | + public: | ||
| 23 | + using ApiCall::Generate; | ||
| 24 | + explicit UnaryOutputApiCall(const std::string &api_name) : ApiCall(api_name) {} | ||
| 25 | + ~UnaryOutputApiCall() override = default; | ||
| 26 | + | ||
| 27 | + Status Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> ¤t_axis, | ||
| 28 | + const std::vector<std::reference_wrapper<const Tensor>> &inputs, | ||
| 29 | + const std::vector<std::reference_wrapper<const Tensor>> &outputs, std::string &result) const override; | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +} // namespace codegen | ||
| 33 | + | ||
| 34 | + | ||
| @@ -898,7 +898,9 @@ build_backend() { | |||
| 898 | chebyshev_polynomial_v_store_test_e2e_v2 \ | 898 | chebyshev_polynomial_v_store_test_e2e_v2 \ |
| 899 | chebyshev_polynomial_w_store_test_e2e_v2 \ | 899 | chebyshev_polynomial_w_store_test_e2e_v2 \ |
| 900 | hermite_polynomial_h_store_test_e2e_v2 \ | 900 | hermite_polynomial_h_store_test_e2e_v2 \ |
| 901 | - hermite_polynomial_he_store_test_e2e_v2" | 901 | + hermite_polynomial_he_store_test_e2e_v2 \ |
| 902 | + rand_store_test_e2e_v2 \ | ||
| 903 | + randn_store_test_e2e_v2" | ||
| 902 | fi | 904 | fi |
| 903 | MAKE_TARGET_LIST_CODEGEN=$(echo "${MAKE_TARGET_LIST}" | sed 's/e2e/codegen/g') | 905 | MAKE_TARGET_LIST_CODEGEN=$(echo "${MAKE_TARGET_LIST}" | sed 's/e2e/codegen/g') |
| 904 | CTEST_BACKEND_TEST1_REGEX=$(build_backend_test_regex ${MAKE_TARGET_LIST_CODEGEN}) | 906 | CTEST_BACKEND_TEST1_REGEX=$(build_backend_test_regex ${MAKE_TARGET_LIST_CODEGEN}) |