diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d7a34d84b..33f3c64f62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,6 +255,15 @@ if(BUILD_TESTING) LABELS "PTO" ENVIRONMENT "${_pto_python_test_env}" ) + add_test( + NAME pto_tload_cache_policy_bindings + COMMAND "${Python3_EXECUTABLE}" + "${CMAKE_CURRENT_SOURCE_DIR}/test/python/tload_cache_policy_bindings.py" + ) + set_tests_properties(pto_tload_cache_policy_bindings PROPERTIES + LABELS "PTO" + ENVIRONMENT "${_pto_python_test_env}" + ) add_test( NAME pto_install_nightly_wheel COMMAND "${Python3_EXECUTABLE}" diff --git a/docs/PTO_IR_manual.md b/docs/PTO_IR_manual.md index 92c0663ccd..cb986ccd8a 100644 --- a/docs/PTO_IR_manual.md +++ b/docs/PTO_IR_manual.md @@ -1168,6 +1168,21 @@ Padding mode for load operations. --- +#### LoadCachePolicy + +Cache allocation policy for one `pto.tload` operation. + +| Value | Int | Description | +|-------|-----|-------------| +| `default` | 0 | Preserve the target's ordinary load and cache behavior | +| `l2_bypass` | 1 | Request a target-defined GM load path that does not allocate in L2 | + +The policy is attached to an individual load, so cached and L2-bypass operands +may be mixed in one kernel. The target library owns the architecture-specific +mechanism; PTOAS never emits an address-alias constant. + +--- + ##### `pto.tload` - Load Partition View to Tile **Summary:** Physical DMA transfer from a global partition view into a local tile buffer. @@ -1193,6 +1208,7 @@ For each element (i, j) in the tile valid region: | `right_padding_num` | `Index` (optional) | Right padding count | | `init_out_buffer` | `BoolAttr` (default: false) | Initialize output buffer | | `init_condition` | `AnyType` (optional) | Init condition | +| `cache_policy` | `LoadCachePolicyAttr` (optional) | Per-load cache allocation policy; absence means `default` | **Results:** None. Writes into `dst` via DPS pattern. @@ -1203,10 +1219,12 @@ For each element (i, j) in the tile valid region: - The destination tile must use `loc=vec` or `loc=mat`. - The destination tile element type and source partition element type must have the same bitwidth. - Runtime: all source partition extents must be positive; the destination valid region must be non-negative. + - `cache_policy=l2_bypass` is supported and lowers to the corresponding typed PTO-ISA `TLOAD` policy. - **Implementation checks (A5)** - The source partition and destination tile element types must be one of `i8/i16/i32/i64/f16/bf16/f32/f8E4M3*/f8E5M2*/!pto.hif8/!pto.f4E1M2x2/!pto.f4E2M1x2`. - The destination tile element size must be `1`, `2`, `4`, or `8` bytes, and must match the source partition element size. - For `i64`, the destination tile `pad` must be `null` or `zero`. + - `cache_policy=l2_bypass` is rejected until the target defines equivalent behavior. **Hardware Mapping:** @@ -1219,6 +1237,14 @@ pto.tload ins(%pv : !pto.partition_tensor_view<16x16xf16>) outs(%tb : !pto.tile_buf) ``` +**L2-bypass example (A2/A3):** + +```mlir +pto.tload ins(%weight : !pto.partition_tensor_view<16x16xf16>) + outs(%weight_tile : !pto.tile_buf) + {cache_policy = #pto.load_cache_policy} +``` + --- ##### `pto.tprefetch` - Prefetch Partition View into Tile diff --git a/docs/isa/tile-op/04-dma-data-movement.md b/docs/isa/tile-op/04-dma-data-movement.md index 6646b7fdfd..e4f7d3fc94 100644 --- a/docs/isa/tile-op/04-dma-data-movement.md +++ b/docs/isa/tile-op/04-dma-data-movement.md @@ -13,6 +13,7 @@ This chapter documents the public tile DMA instructions `pto.tload` and `pto.tst ```mlir pto.tload ins(%src : !pto.partition_tensor_view<...>) outs(%dst : !pto.tile_buf<...>) + {cache_policy = #pto.load_cache_policy} ``` - **semantics:** Physical DMA transfer from a global partition view into a local tile buffer. For each element `(i, j)` in the destination valid region: `dst[i, j] = src[i, j]`. @@ -22,6 +23,7 @@ pto.tload ins(%src : !pto.partition_tensor_view<...>) |-----------|------|-------------| | `src` | `PartitionTensorViewType` | Source partition view. | | `dst` | `pto.tile_buf` | Destination tile buffer. | +| `cache_policy` | `LoadCachePolicyAttr` (optional) | `default` when absent; `l2_bypass` requests a non-allocating L2 path for this load. | **Constraints:** @@ -29,6 +31,8 @@ pto.tload ins(%src : !pto.partition_tensor_view<...>) - Destination tile must use `loc=vec`. - Destination tile element type and source partition element type must have the same bitwidth. - Runtime: source partition extents and destination valid region must be positive. +- `l2_bypass` is currently supported on A2/A3 and rejected on A5. +- PTO-ISA owns the target-specific bypass mechanism; PTOAS emits no address-alias constant. **Pipeline:** `PIPE_MTE2`. @@ -39,6 +43,10 @@ pto.tload ins(%pv : !pto.partition_tensor_view<16x16xf16>) outs(%tb : !pto.tile_buf) ``` +When `cache_policy` is absent or `default`, PTOAS emits the legacy +`TLOAD(dst, src)` call. `l2_bypass` emits +`TLOAD(dst, src)`. + --- ## `pto.tstore` diff --git a/include/PTO/IR/PTOAttrs.td b/include/PTO/IR/PTOAttrs.td index 283d9ab105..88f56f170f 100644 --- a/include/PTO/IR/PTOAttrs.td +++ b/include/PTO/IR/PTOAttrs.td @@ -75,6 +75,27 @@ def PTO_AddressSpaceAttr : PTO_Attr<"AddressSpace", "address_space"> { }]; } +//===----------------------------------------------------------------------===// +// Tile load cache policy +//===----------------------------------------------------------------------===// + +def PTO_LoadCachePolicyEnum : PTO_I32Enum< + "LoadCachePolicy", "PTO tile load cache policy", [ + I32EnumAttrCase<"Default", 0, "default">, + I32EnumAttrCase<"L2Bypass", 1, "l2_bypass"> + ]>; + +def PTO_LoadCachePolicyAttr + : EnumAttr { + let assemblyFormat = "`<` params `>`"; + let summary = "cache allocation policy for a tile load"; + let description = [{ + Selects the cache allocation policy for one GM-to-tile transfer. The + default policy preserves the target's ordinary load behavior. L2Bypass + requests a target-defined load path that does not allocate in L2. + }]; +} + //===----------------------------------------------------------------------===// // Signedness //===----------------------------------------------------------------------===// diff --git a/include/PTO/IR/PTOOps.td b/include/PTO/IR/PTOOps.td index a72e21c7b4..3d29900bbb 100644 --- a/include/PTO/IR/PTOOps.td +++ b/include/PTO/IR/PTOOps.td @@ -602,7 +602,8 @@ def TLoadOp : PTO_TOp<"tload", [ Optional:$left_padding_num, Optional:$right_padding_num, DefaultValuedOptionalAttr:$init_out_buffer, - Optional:$init_condition + Optional:$init_condition, + OptionalAttr:$cache_policy ); let results = (outs @@ -617,21 +618,23 @@ def TLoadOp : PTO_TOp<"tload", [ build($_builder, $_state, res, src, dst, /*pad_mode=*/nullptr, /*pad_value=*/nullptr, /*left=*/nullptr, /*right=*/nullptr, - /*init_out=*/nullptr, /*init_cond=*/nullptr); + /*init_out=*/nullptr, /*init_cond=*/nullptr, + /*cache_policy=*/nullptr); }]>, // 2. With left_padding_num OpBuilder<(ins "TypeRange":$res, "Value":$src, "Value":$dst, "Value":$left_padding_num), [{ build($_builder, $_state, res, src, dst, - nullptr, nullptr, left_padding_num, nullptr, nullptr, nullptr); + nullptr, nullptr, left_padding_num, nullptr, nullptr, nullptr, + nullptr); }]>, // 3. With pad_mode, pad_value OpBuilder<(ins "TypeRange":$res, "Value":$src, "Value":$dst, "pto::PadModeAttr":$pad_mode, "Value":$pad_value), [{ build($_builder, $_state, res, src, dst, - pad_mode, pad_value, nullptr, nullptr, nullptr, nullptr); + pad_mode, pad_value, nullptr, nullptr, nullptr, nullptr, nullptr); }]>, // 4. ... + left @@ -639,7 +642,8 @@ def TLoadOp : PTO_TOp<"tload", [ "pto::PadModeAttr":$pad_mode, "Value":$pad_value, "Value":$left_padding_num), [{ build($_builder, $_state, res, src, dst, - pad_mode, pad_value, left_padding_num, nullptr, nullptr, nullptr); + pad_mode, pad_value, left_padding_num, nullptr, nullptr, nullptr, + nullptr); }]>, // 5. ... + left + right @@ -647,7 +651,8 @@ def TLoadOp : PTO_TOp<"tload", [ "pto::PadModeAttr":$pad_mode, "Value":$pad_value, "Value":$left_padding_num, "Value":$right_padding_num), [{ build($_builder, $_state, res, src, dst, - pad_mode, pad_value, left_padding_num, right_padding_num, nullptr, nullptr); + pad_mode, pad_value, left_padding_num, right_padding_num, nullptr, + nullptr, nullptr); }]>, // 6. ... + left + right + bool @@ -657,7 +662,7 @@ def TLoadOp : PTO_TOp<"tload", [ "bool":$init_out_buffer), [{ build($_builder, $_state, res, src, dst, pad_mode, pad_value, left_padding_num, right_padding_num, - init_out_buffer, nullptr); + init_out_buffer, nullptr, nullptr); }]> ]; diff --git a/include/pto-c/Dialect/PTO.h b/include/pto-c/Dialect/PTO.h index c506384a28..9ad8143ecd 100644 --- a/include/pto-c/Dialect/PTO.h +++ b/include/pto-c/Dialect/PTO.h @@ -62,6 +62,14 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirPTOAddressSpaceAttrGet(MlirContext ctx, int // Read back enum value (0..6) MLIR_CAPI_EXPORTED int32_t mlirPTOAddressSpaceAttrGetValue(MlirAttribute attr); +// ---- #pto.load_cache_policy<...> ---- +MLIR_CAPI_EXPORTED bool +mlirPTOAttrIsALoadCachePolicyAttr(MlirAttribute attr); +MLIR_CAPI_EXPORTED MlirAttribute +mlirPTOLoadCachePolicyAttrGet(MlirContext ctx, int32_t value); +MLIR_CAPI_EXPORTED int32_t +mlirPTOLoadCachePolicyAttrGetValue(MlirAttribute attr); + // ---- !pto.tensor_view ---- MLIR_CAPI_EXPORTED bool mlirPTOTypeIsATensorViewType(MlirType type); MLIR_CAPI_EXPORTED MlirType mlirPTOTensorViewTypeGet(MlirContext ctx, intptr_t rank, diff --git a/lib/Bindings/Python/PTOModule.cpp b/lib/Bindings/Python/PTOModule.cpp index 818a214354..c72f8fcfed 100644 --- a/lib/Bindings/Python/PTOModule.cpp +++ b/lib/Bindings/Python/PTOModule.cpp @@ -160,6 +160,9 @@ void mlir::pto::python::populatePTODialectBindings(pybind11::module_ &m) { .value("GM", mlir::pto::FenceScope::GM) .value("All", mlir::pto::FenceScope::All) .export_values(); + py::enum_(m, "LoadCachePolicy") + .value("Default", mlir::pto::LoadCachePolicy::Default) + .value("L2Bypass", mlir::pto::LoadCachePolicy::L2Bypass); py::enum_(m, "BLayout") .value("RowMajor", mlir::pto::BLayout::RowMajor) .value("ColMajor", mlir::pto::BLayout::ColMajor); @@ -551,6 +554,11 @@ void mlir::pto::python::populatePTODialectBindings(pybind11::module_ &m) { return mlirPTOFenceScopeAttrGetValue(self); }); + bindPTOEnumAttr(m, "LoadCachePolicyAttr", "LoadCachePolicy", + mlirPTOAttrIsALoadCachePolicyAttr, + mlirPTOLoadCachePolicyAttrGet, + mlirPTOLoadCachePolicyAttrGetValue); + mlir_attribute_subclass( m, "RoundModeAttr", [](MlirAttribute a) { return mlirPTOAttrIsARoundModeAttr(a); }) diff --git a/lib/CAPI/Dialect/PTO.cpp b/lib/CAPI/Dialect/PTO.cpp index 4966e2f3c1..2bd1da2ba1 100644 --- a/lib/CAPI/Dialect/PTO.cpp +++ b/lib/CAPI/Dialect/PTO.cpp @@ -187,6 +187,26 @@ int32_t mlirPTOAddressSpaceAttrGetValue(MlirAttribute attr) { return static_cast(a.getAddressSpace()); } +bool mlirPTOAttrIsALoadCachePolicyAttr(MlirAttribute attr) { + return mlir::isa(unwrap(attr)); +} + +MlirAttribute mlirPTOLoadCachePolicyAttrGet(MlirContext ctx, int32_t value) { + const bool isValidPolicy = + value >= static_cast(mlir::pto::LoadCachePolicy::Default) && + value <= static_cast(mlir::pto::LoadCachePolicy::L2Bypass); + if (!isValidPolicy) { + return MlirAttribute{nullptr}; + } + auto policy = static_cast(value); + return wrap(mlir::pto::LoadCachePolicyAttr::get(unwrap(ctx), policy)); +} + +int32_t mlirPTOLoadCachePolicyAttrGetValue(MlirAttribute attr) { + auto policy = mlir::cast(unwrap(attr)); + return static_cast(policy.getValue()); +} + //===----------------------------------------------------------------------===// // Type queries / constructors for !pto.tensor_view //===----------------------------------------------------------------------===// diff --git a/lib/PTO/IR/PTO.cpp b/lib/PTO/IR/PTO.cpp index 9191a3f0d3..153690a5b2 100644 --- a/lib/PTO/IR/PTO.cpp +++ b/lib/PTO/IR/PTO.cpp @@ -3863,6 +3863,13 @@ LogicalResult TLoadOp::verify() { }; auto verifyA5 = [&]() -> LogicalResult { + if (auto policy = getCachePolicyAttr(); + policy && policy.getValue() == pto::LoadCachePolicy::L2Bypass) { + return emitOpError( + "does not support cache_policy=l2_bypass on A5; the policy is " + "currently supported only on A2/A3"); + } + auto common = verifyCommon(/*allowLowPrecision=*/true); if (failed(common)) { return failure(); diff --git a/lib/PTO/Transforms/ConvertToPTOOp.cpp b/lib/PTO/Transforms/ConvertToPTOOp.cpp index 59dd0b2dfb..1a51cb74e7 100644 --- a/lib/PTO/Transforms/ConvertToPTOOp.cpp +++ b/lib/PTO/Transforms/ConvertToPTOOp.cpp @@ -109,7 +109,9 @@ LogicalResult replaceMemCopyByPTOLoadOp(memref::CopyOp copyOp, auto maybeLeftPadNum = getLeftPadNum(rewriter, maybeAlloc); auto loadOp = rewriter.create(copyOp->getLoc(), TypeRange(), - copyOp.getSource(), dst, nullptr, nullptr, nullptr, nullptr, false, nullptr); + copyOp.getSource(), dst, nullptr, + nullptr, nullptr, nullptr, false, + nullptr, nullptr); if (maybeLeftPadNum.has_value()) { loadOp.getLeftPaddingNumMutable().assign(maybeLeftPadNum.value()); } diff --git a/lib/PTO/Transforms/PTOToEmitC.cpp b/lib/PTO/Transforms/PTOToEmitC.cpp index 1a35699d48..36bbb9dad9 100644 --- a/lib/PTO/Transforms/PTOToEmitC.cpp +++ b/lib/PTO/Transforms/PTOToEmitC.cpp @@ -4809,8 +4809,15 @@ struct PTOTLoadToTLOAD : public OpConversionPattern { Value src = peelGlobalTensorConversionBridge(adaptor.getSrc()); Value dst = adaptor.getDst(); + ArrayAttr templateArgs = ArrayAttr{}; + if (auto policy = op.getCachePolicyAttr(); + policy && policy.getValue() == pto::LoadCachePolicy::L2Bypass) { + templateArgs = rewriter.getArrayAttr({emitc::OpaqueAttr::get( + rewriter.getContext(), "pto::LoadCachePolicy::L2Bypass")}); + } + rewriter.create(op.getLoc(), TypeRange{}, "TLOAD", - ArrayAttr{}, ArrayAttr{}, + ArrayAttr{}, templateArgs, ValueRange{dst, src}); if (op->getNumResults() == 1) { diff --git a/python/pto/dialects/pto.py b/python/pto/dialects/pto.py index 95d88d18f1..f1a24d5558 100644 --- a/python/pto/dialects/pto.py +++ b/python/pto/dialects/pto.py @@ -65,6 +65,8 @@ def _export_optional_cext_symbol(name): AddressSpaceAttr = _pto_mod.AddressSpaceAttr FenceScope = _pto_mod.FenceScope FenceScopeAttr = _pto_mod.FenceScopeAttr +LoadCachePolicy = _pto_mod.LoadCachePolicy +LoadCachePolicyAttr = _pto_mod.LoadCachePolicyAttr TileBufConfigAttr = _pto_mod.TileBufConfigAttr BLayout = _pto_mod.BLayout BLayoutAttr = _pto_mod.BLayoutAttr @@ -212,12 +214,18 @@ def address_space_attr_builder(value, context=None): def fence_scope_attr_builder(value, context=None): return FenceScopeAttr.get(value, context) + def load_cache_policy_attr_builder(value, context=None): + return LoadCachePolicyAttr.get(value, context) + _ods_ir.AttrBuilder.insert( "PTO_AddressSpaceAttr", address_space_attr_builder, replace=True ) _ods_ir.AttrBuilder.insert( "PTO_FenceScopeAttr", fence_scope_attr_builder, replace=True ) + _ods_ir.AttrBuilder.insert( + "PTO_LoadCachePolicyAttr", load_cache_policy_attr_builder, replace=True + ) _install_enum_attr_builders() @@ -248,6 +256,8 @@ def fence_scope_attr_builder(value, context=None): "AddressSpaceAttr", "FenceScope", "FenceScopeAttr", + "LoadCachePolicy", + "LoadCachePolicyAttr", "BLayout", "BLayoutAttr", "SLayout", diff --git a/test/lit/pto/tload_cache_policy.pto b/test/lit/pto/tload_cache_policy.pto new file mode 100644 index 0000000000..a404f0e8d7 --- /dev/null +++ b/test/lit/pto/tload_cache_policy.pto @@ -0,0 +1,48 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// RUN: ptoas --pto-level=level3 --pto-arch=a3 --emit-pto-ir %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=PTOIR +// RUN: ptoas --pto-level=level3 --pto-arch=a3 %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=EMITC +// RUN: not ptoas --pto-level=level3 --pto-arch=a5 %s -o /dev/null 2>&1 \ +// RUN: | FileCheck %s --check-prefix=A5-ERR + +module { + func.func private @default_load( + %src: !pto.partition_tensor_view<16x16xf32>, + %dst: !pto.tile_buf) { + pto.tload ins(%src : !pto.partition_tensor_view<16x16xf32>) + outs(%dst : !pto.tile_buf) + return + } + + func.func private @l2_bypass_load( + %src: !pto.partition_tensor_view<16x16xf32>, + %dst: !pto.tile_buf) { + pto.tload ins(%src : !pto.partition_tensor_view<16x16xf32>) + outs(%dst : !pto.tile_buf) + {cache_policy = #pto.load_cache_policy} + return + } +} + +// PTOIR-LABEL: func.func private @default_load( +// PTOIR: pto.tload ins( +// PTOIR-NOT: cache_policy +// PTOIR-LABEL: func.func private @l2_bypass_load( +// PTOIR: pto.tload ins( +// PTOIR-SAME: cache_policy = #pto.load_cache_policy + +// EMITC-LABEL: default_load( +// EMITC: TLOAD( +// EMITC-LABEL: l2_bypass_load( +// EMITC: TLOAD( +// EMITC-NOT: 0x80000000000 + +// A5-ERR: 'pto.tload' op does not support cache_policy=l2_bypass on A5 diff --git a/test/python/tload_cache_policy_bindings.py b/test/python/tload_cache_policy_bindings.py new file mode 100644 index 0000000000..4b3ae0629d --- /dev/null +++ b/test/python/tload_cache_policy_bindings.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. + +from ptoas.mlir.ir import Context, Location +from ptoas.mlir.dialects import pto + + +def main() -> None: + with Context() as ctx, Location.unknown(ctx): + pto.register_dialect(ctx, load=True) + policy = pto.LoadCachePolicyAttr.get(pto.LoadCachePolicy.L2Bypass) + if str(policy) != "#pto.load_cache_policy": + raise RuntimeError(f"unexpected load cache policy: {policy}") + if policy.value != pto.LoadCachePolicy.L2Bypass.value: + raise RuntimeError(f"unexpected load cache policy value: {policy.value}") + + print("tload_cache_policy_bindings: PASS") + + +if __name__ == "__main__": + main() diff --git a/tools/ptobc/testdata/tload_cache_policy_v0_roundtrip.pto b/tools/ptobc/testdata/tload_cache_policy_v0_roundtrip.pto new file mode 100644 index 0000000000..bc6dfeec7e --- /dev/null +++ b/tools/ptobc/testdata/tload_cache_policy_v0_roundtrip.pto @@ -0,0 +1,18 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +module { + func.func @tload_cache_policy_v0_roundtrip( + %src: !pto.partition_tensor_view<16x16xf32>, + %dst: !pto.tile_buf) { + pto.tload ins(%src : !pto.partition_tensor_view<16x16xf32>) + outs(%dst : !pto.tile_buf) + {cache_policy = #pto.load_cache_policy} + return + } +} diff --git a/tools/ptobc/tests/CMakeLists.txt b/tools/ptobc/tests/CMakeLists.txt index cc170a6bef..628b4cdc42 100644 --- a/tools/ptobc/tests/CMakeLists.txt +++ b/tools/ptobc/tests/CMakeLists.txt @@ -187,3 +187,10 @@ add_test(NAME ptobc_tcvt_satmode_v0_encode TESTDATA_DIR=${PTObc_TESTDATA_DIR} ${CMAKE_CURRENT_LIST_DIR}/tcvt_satmode_v0_encode.sh ) + +add_test(NAME ptobc_tload_cache_policy_v0_encode + COMMAND ${CMAKE_COMMAND} -E env + PTOBC_BIN=$ + TESTDATA_DIR=${PTObc_TESTDATA_DIR} + bash ${CMAKE_CURRENT_LIST_DIR}/tload_cache_policy_v0_encode.sh +) diff --git a/tools/ptobc/tests/tload_cache_policy_v0_encode.sh b/tools/ptobc/tests/tload_cache_policy_v0_encode.sh new file mode 100644 index 0000000000..7e6c96c3ca --- /dev/null +++ b/tools/ptobc/tests/tload_cache_policy_v0_encode.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. + +set -euo pipefail + +PTOBC_BIN=${PTOBC_BIN:-} +TESTDATA_DIR=${TESTDATA_DIR:-} +if [[ -z "${PTOBC_BIN}" || -z "${TESTDATA_DIR}" ]]; then + echo "error: PTOBC_BIN and TESTDATA_DIR must be set" >&2 + exit 2 +fi + +IN="${TESTDATA_DIR}/tload_cache_policy_v0_roundtrip.pto" +OUT_DIR=${OUT_DIR:-"${PWD}/ptobc_tload_cache_policy_out"} +mkdir -p "${OUT_DIR}" + +BC="${OUT_DIR}/tload_cache_policy_v0_roundtrip.ptobc" +ROUNDTRIP="${OUT_DIR}/tload_cache_policy_v0_roundtrip.roundtrip.pto" + +"${PTOBC_BIN}" encode "${IN}" -o "${BC}" +"${PTOBC_BIN}" decode "${BC}" -o "${ROUNDTRIP}" + +grep -F "pto.tload ins(" "${ROUNDTRIP}" >/dev/null +grep -F "cache_policy = #pto.load_cache_policy" "${ROUNDTRIP}" >/dev/null