已合并
补充hf32模式支持及文档更新 #1133
init__zhb__创建于 22 天前
补充hf32模式支持及文档更新 #1133
已合并
init__zhb__创建于 22 天前
36 个文件变更+545-258
@@ -154,8 +154,8 @@ Kernel 对象(调优与特性查询)
154 154 
155详细参考使用示例和 API 文档请参考下述文档:155详细参考使用示例和 API 文档请参考下述文档:
156 - [Kernel API 基础文档](docs/kernel_api.md)156 - [Kernel API 基础文档](docs/kernel_api.md)
157- - OpTensor API 基础文档(文档暂缺)157+ - [`OpTensor` 基础文档](docs/optensor_api.md)
CheaterAbec
CheaterAbecCheaterAbec22 天前

关联一下issue

likedislike
init__zhb__
22 天前 评论:
158- - [EVG API 基础文档](docs/evg_api.md)158+ - [`EVG` 基础文档](docs/evg_api.md)
CheaterAbec
CheaterAbecCheaterAbec22 天前

为什么要带上cppgen的修改?缩小PR改动面

likedislike
init__zhb__
22 天前 评论:
CheaterAbec
CheaterAbec
22 天前 评论:
159 159 
160### 4.1 基础 GEMM160### 4.1 基础 GEMM
161 161 
@@ -1,6 +1,6 @@
1-# EVG API (Python)1+# `EVG` 基础文档 (Python)
2 2 
3-节记录了 CATLASS 中 [EVG(Epilogue Visitor Graph)模块](../../../docs/zh/2_Design/03_evg/01_evg_design.md)的 Python API。EVG 将 Python 描述的 epilogue 后处理函数解析为 DAG,并生成对应的 C++ Visitor 代码。3+文档为 `catlass_cppgen` 中 [EVG(Epilogue Visitor Graph)模块](../../../docs/zh/2_Design/03_evg/01_evg_design.md)的使用说明。EVG 将 Python 描述的 epilogue 后处理函数解析为 DAG(Directed Acyclic Graph有向无环图),并生成对应的 C++ Visitor 代码。
4 4 
5核心入口函数定义见 [`evg_extension.py`](../catlass_cppgen/catlass/evg_extension.py),节点与定义见 [`evg/`](../catlass_cppgen/catlass/evg/)。5核心入口函数定义见 [`evg_extension.py`](../catlass_cppgen/catlass/evg_extension.py),节点与定义见 [`evg/`](../catlass_cppgen/catlass/evg/)。
6 6 
@@ -1,6 +1,6 @@
1-# OpTensor 基础 Api (Python)1+# `OpTensor` 基础文档 (Python)
2 2 
3-本文档详细描述了 `catlass_cppgen` 中所有支持的`OpTensor`创建方式,及关联的基础特性如数据类型,布局分布等。3+本文档 `catlass_cppgen` 中 `OpTensor` 的使用说明,介绍其创建方法、基础特性如数据类型,布局分布等。
4 4 
5---5---
6 6 
@@ -1830,7 +1830,7 @@ class MmadOp(_ods_ir.OpView):
1830 1830 
1831 _ODS_REGIONS = (0, True)1831 _ODS_REGIONS = (0, True)
1832 1832 
1833- def __init__(self, acc, lhs, rhs, init_c, unit_flag, compute_order, *, loc=None, ip=None):1833+ def __init__(self, acc, lhs, rhs, init_c, unit_flag, compute_order, hf32_mode, *, loc=None, ip=None):
1834 operands = []1834 operands = []
1835 results = []1835 results = []
1836 attributes = {}1836 attributes = {}
@@ -1845,6 +1845,10 @@ class MmadOp(_ods_ir.OpView):
1845 isinstance(compute_order, _ods_ir.Attribute) or1845 isinstance(compute_order, _ods_ir.Attribute) or
1846 not _ods_ir.AttrBuilder.contains('Tla_ComputeOrderAttr')) else1846 not _ods_ir.AttrBuilder.contains('Tla_ComputeOrderAttr')) else
1847 _ods_ir.AttrBuilder.get('Tla_ComputeOrderAttr')(compute_order, context=_ods_context))1847 _ods_ir.AttrBuilder.get('Tla_ComputeOrderAttr')(compute_order, context=_ods_context))
1848+ attributes["hf32_mode"] = (hf32_mode if (
1849+ isinstance(hf32_mode, _ods_ir.Attribute) or
1850+ not _ods_ir.AttrBuilder.contains('Tla_HF32ModeAttr')) else
1851+ _ods_ir.AttrBuilder.get('Tla_HF32ModeAttr')(hf32_mode, context=_ods_context))
1848 _ods_successors = None1852 _ods_successors = None
1849 super().__init__(self.build_generic(attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip))1853 super().__init__(self.build_generic(attributes=attributes, results=results, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip))
1850 1854 
@@ -1878,8 +1882,18 @@ class MmadOp(_ods_ir.OpView):
1878 raise ValueError("'None' not allowed as value for mandatory attributes")1882 raise ValueError("'None' not allowed as value for mandatory attributes")
1879 self.operation.attributes["compute_order"] = value1883 self.operation.attributes["compute_order"] = value
1880 1884 
1881-def mmad(acc, lhs, rhs, init_c, unit_flag, compute_order, *, loc=None, ip=None) -> _ods_ir.Operation:1885+ @builtins.property
1882- return _get_op_result_or_op_results(MmadOp(acc=acc, lhs=lhs, rhs=rhs, init_c=init_c, unit_flag=unit_flag, compute_order=compute_order, loc=loc, ip=ip))1886+ def hf32_mode(self):
1887+ return self.operation.attributes["hf32_mode"]
1888+ 
1889+ @hf32_mode.setter
1890+ def hf32_mode(self, value):
1891+ if value is None:
1892+ raise ValueError("'None' not allowed as value for mandatory attributes")
1893+ self.operation.attributes["hf32_mode"] = value
1894+ 
1895+def mmad(acc, lhs, rhs, init_c, unit_flag, compute_order, hf32_mode, *, loc=None, ip=None) -> _ods_ir.Operation:
1896+ return _get_op_result_or_op_results(MmadOp(acc=acc, lhs=lhs, rhs=rhs, init_c=init_c, unit_flag=unit_flag, compute_order=compute_order, hf32_mode=hf32_mode, loc=loc, ip=ip))
1883 1897 
1884@_ods_cext.register_operation(_Dialect)1898@_ods_cext.register_operation(_Dialect)
1885class MulOp(_ods_ir.OpView):1899class MulOp(_ods_ir.OpView):
@@ -61,13 +61,14 @@ from .types import (
61 _replace_flat_leaves_in_tree,61 _replace_flat_leaves_in_tree,
62)62)
63from .params import (63from .params import (
64- CopyParams,
65- CopyL0C2DstParams,
66- QuantMode,
67- L0C2UBMode,
68 AtomicMode,64 AtomicMode,
65+ HF32Mode,
69 ComputeOrder,66 ComputeOrder,
67+ CopyL0C2DstParams,
68+ CopyParams,
69+ L0C2UBMode,
70 MemType,70 MemType,
71+ QuantMode,
71)72)
72 73 
73 74 
@@ -5180,6 +5181,7 @@ def mmad(
5180 init_c: bool | Bool | None = None,5181 init_c: bool | Bool | None = None,
5181 unit_flag: IndexLike | None = None,5182 unit_flag: IndexLike | None = None,
5182 compute_order: ComputeOrder = ComputeOrder.M_FIRST,5183 compute_order: ComputeOrder = ComputeOrder.M_FIRST,
5184+ hf32_mode: HF32Mode = HF32Mode.HF32_DISABLE,
5183 loc: mlir_ir.Location | None = None,5185 loc: mlir_ir.Location | None = None,
5184 **extra_kwargs: object,5186 **extra_kwargs: object,
5185) -> None:5187) -> None:
@@ -5196,6 +5198,8 @@ def mmad(
5196 - `unit_flag` (`IndexLike | None`): Unit-flag control bits; defaults to `0`5198 - `unit_flag` (`IndexLike | None`): Unit-flag control bits; defaults to `0`
5197 when omitted. Optional, default `None`.5199 when omitted. Optional, default `None`.
5198 - `compute_order` (`ComputeOrder`): M/N compute-direction priority; default `M_FIRST`.5200 - `compute_order` (`ComputeOrder`): M/N compute-direction priority; default `M_FIRST`.
5201+ - `hf32_mode` (`HF32Mode`): HF32 rounding mode for FP32 operands in L0A/L0B
5202+ before the matrix multiply. Optional, default `HF32_DISABLE`.
5199 5203 
5200 Constraints:5204 Constraints:
5201 - Must be called inside a `@tla.kernel`-decorated kernel function.5205 - Must be called inside a `@tla.kernel`-decorated kernel function.
@@ -5253,10 +5257,18 @@ def mmad(
5253 "tla.mmad attribute 'compute_order' must be a "5257 "tla.mmad attribute 'compute_order' must be a "
5254 f"{ComputeOrder}, got {type(compute_order).__name__}"5258 f"{ComputeOrder}, got {type(compute_order).__name__}"
5255 )5259 )
5260+ if not isinstance(hf32_mode, HF32Mode):
5261+ raise TlaLoweringError(
5262+ "tla.mmad attribute 'hf32_mode' must be a "
5263+ f"{HF32Mode}, got {type(hf32_mode).__name__}"
5264+ )
5256 ctx = loc.context if loc is not None else mlir_ir.Context.current5265 ctx = loc.context if loc is not None else mlir_ir.Context.current
5257 compute_order_attr = mlir_ir.Attribute.parse(5266 compute_order_attr = mlir_ir.Attribute.parse(
5258 f"#tla.compute_order<{str(compute_order)}>", context=ctx5267 f"#tla.compute_order<{str(compute_order)}>", context=ctx
5259 )5268 )
5269+ hf32_mode_attr = mlir_ir.Attribute.parse(
5270+ f"#tla.hf32_mode<{str(hf32_mode)}>", context=ctx
5271+ )
5260 5272 
5261 acc_value = _as_value(acc)5273 acc_value = _as_value(acc)
5262 lhs_value = _as_value(lhs)5274 lhs_value = _as_value(lhs)
@@ -5270,6 +5282,7 @@ def mmad(
5270 unit_flag_value,5282 unit_flag_value,
5271 loc=loc,5283 loc=loc,
5272 compute_order=compute_order_attr,5284 compute_order=compute_order_attr,
5285+ hf32_mode=hf32_mode_attr,
5273 )5286 )
5274 5287 
5275 5288 
@@ -33,6 +33,15 @@ class ComputeOrder(enum.IntEnum):
33 return self.name # "M_FIRST"/"N_FIRST"33 return self.name # "M_FIRST"/"N_FIRST"
34 34 
35 35 
36+class HF32Mode(enum.IntEnum):
37+ HF32_DISABLE = 0
38+ HF32_NEAREST_ZERO = 1
39+ HF32_NEAREST_EVEN = 2
40+ 
41+ def __str__(self):
42+ return self.name # "HF32_DISABLE"/"HF32_NEAREST_ZERO"/"HF32_NEAREST_EVEN"
43+ 
44+ 
36class AtomicMode(enum.Enum):45class AtomicMode(enum.Enum):
37 """Atomic operation mode"""46 """Atomic operation mode"""
38 47 
@@ -382,6 +382,27 @@ def Tla_ComputeOrderAttr : Tla_EnumAttr<"ComputeOrder", "compute_order"> {
382 }];382 }];
383}383}
384 384 
385+// HF32Mode: mmad HF32 rounding mode (CTRL[46] enable, CTRL[47] rounding).
386+// HF32_DISABLE(0) is the hardware default (no HF32 rounding).
387+def Tla_HF32Mode_Disable : I32EnumAttrCase<"HF32_DISABLE", 0>;
388+def Tla_HF32Mode_NearestZero : I32EnumAttrCase<"HF32_NEAREST_ZERO", 1>;
389+def Tla_HF32Mode_NearestEven : I32EnumAttrCase<"HF32_NEAREST_EVEN", 2>;
390+def Tla_HF32Mode_Enum : Tla_I32Enum<"HF32Mode",
391+ "mmad HF32 rounding mode", [
392+ Tla_HF32Mode_Disable, Tla_HF32Mode_NearestZero, Tla_HF32Mode_NearestEven
393+]>;
394+def Tla_HF32ModeAttr : Tla_EnumAttr<"HF32Mode", "hf32_mode"> {
395+ let parameters = (ins EnumParameter<Tla_HF32Mode_Enum>:$value);
396+ let assemblyFormat = "`<` params `>`";
397+ let description = [{
398+ mmad HF32 rounding mode, lowered to SPR.CTRL[46]/CTRL[47]:
399+ 
400+ - HF32_DISABLE (0): HF32 mode disabled (hardware default)
401+ - HF32_NEAREST_ZERO (1): f32 rounded to HF32 towards zero
402+ - HF32_NEAREST_EVEN (2): f32 rounded to HF32 to nearest even
403+ }];
404+}
405+ 
385// SatMode: overflow behaviour of the cast (AVE `sat` BoolAttr).406// SatMode: overflow behaviour of the cast (AVE `sat` BoolAttr).
386def Tla_SatMode_Unknown : I32EnumAttrCase<"unknown", 0>;407def Tla_SatMode_Unknown : I32EnumAttrCase<"unknown", 0>;
387def Tla_SatMode_Sat : I32EnumAttrCase<"sat", 1>;408def Tla_SatMode_Sat : I32EnumAttrCase<"sat", 1>;
@@ -857,10 +878,19 @@ def Tla_MmadOp : Tla_Op<"mmad", []> {
857 every mmad in a function agrees on the value it is emitted once at the878 every mmad in a function agrees on the value it is emitted once at the
858 function entry; if a function mixes values it is emitted ahead of each mmad879 function entry; if a function mixes values it is emitted ahead of each mmad
859 runtime call instead.880 runtime call instead.
881+ 
882+ ``hf32_mode`` is always supplied by the frontend. The lowering emits
883+ ``hivm.set_ctrl`` on ``CTRL[46]`` (enable HF32 rounding) and ``CTRL[47]``
884+ (rounding mode, ``HF32_NEAREST_ZERO`` -> 1 / ``HF32_NEAREST_EVEN`` -> 0,
885+ mirroring ``AscendC::SetHF32Mode`` / ``AscendC::SetHF32TransMode``): when
886+ every mmad in a function agrees on the value it is emitted once at the
887+ function entry; if a function mixes values it is emitted ahead of each mmad
888+ runtime call instead.
860 }];889 }];
861 let arguments = (ins Tla_TensorType:$acc, Tla_TensorType:$lhs, Tla_TensorType:$rhs,890 let arguments = (ins Tla_TensorType:$acc, Tla_TensorType:$lhs, Tla_TensorType:$rhs,
862 I1:$init_c, I64:$unit_flag,891 I1:$init_c, I64:$unit_flag,
863- Tla_ComputeOrderAttr:$compute_order);892+ Tla_ComputeOrderAttr:$compute_order,
893+ Tla_HF32ModeAttr:$hf32_mode);
864 let assemblyFormat = [{894 let assemblyFormat = [{
865 $acc `,` $lhs `,` $rhs `,` $init_c `,` $unit_flag attr-dict `:`895 $acc `,` $lhs `,` $rhs `,` $init_c `,` $unit_flag attr-dict `:`
866 qualified(type($acc)) `,` qualified(type($lhs)) `,` qualified(type($rhs)) `,` type($init_c) `,` type($unit_flag)896 qualified(type($acc)) `,` qualified(type($lhs)) `,` qualified(type($rhs)) `,` type($init_c) `,` type($unit_flag)
@@ -224,6 +224,20 @@ Attribute TlaDialect::parseAttribute(DialectAsmParser& parser, Type type) const
224 return ::tla::ComputeOrderAttr::get(getContext(), *symbolized);224 return ::tla::ComputeOrderAttr::get(getContext(), *symbolized);
225 }225 }
226 226 
227+ if (attrTag == "hf32_mode") {
228+ if (parser.parseLess())
229+ return {};
230+ StringRef modeKeyword;
231+ if (parser.parseKeyword(&modeKeyword) || parser.parseGreater())
232+ return {};
233+ auto symbolized = ::symbolizeHF32Mode(modeKeyword);
234+ if (!symbolized) {
235+ parser.emitError(parser.getNameLoc()) << "invalid tla.hf32_mode value: " << modeKeyword;
236+ return {};
237+ }
238+ return ::tla::HF32ModeAttr::get(getContext(), *symbolized);
239+ }
240+ 
227 StringRef mnemonic = attrTag;241 StringRef mnemonic = attrTag;
228 Attribute value;242 Attribute value;
229 OptionalParseResult parseResult = generatedAttributeParser(parser, &mnemonic, type, value);243 OptionalParseResult parseResult = generatedAttributeParser(parser, &mnemonic, type, value);
@@ -279,6 +279,26 @@ mlir::LogicalResult MmadOp::verify()
279{279{
280 if (!hasEnclosingRegion<CubeOp>(getOperation()))280 if (!hasEnclosingRegion<CubeOp>(getOperation()))
281 return emitOpError("must be nested inside a tla.cube region");281 return emitOpError("must be nested inside a tla.cube region");
282+ 
283+ // HF32 rounding only applies to f32 L0A/L0B operands; requesting it for any
284+ // other source element type (f16/bf16/...) is meaningless and must be rejected.
285+ HF32Mode mode = getHf32Mode().getValue();
286+ if (mode != HF32Mode::HF32_DISABLE) {
287+ auto checkF32SourceOperand = [&](TlaTensorType operandType,
288+ llvm::StringRef operandName) -> mlir::LogicalResult {
289+ mlir::Type elementType = operandType.getPtr().getPointee();
290+ if (!elementType.isF32())
291+ return emitOpError() << "hf32_mode " << stringifyHF32Mode(mode) << " requires f32 source operands, but "
292+ << operandName << " operand has element type " << elementType;
293+ return mlir::success();
294+ };
295+ 
296+ if (failed(checkF32SourceOperand(getLhs().getType(), "lhs")))
297+ return mlir::failure();
298+ if (failed(checkF32SourceOperand(getRhs().getType(), "rhs")))
299+ return mlir::failure();
300+ }
301+ 
282 return mlir::success();302 return mlir::success();
283}303}
284 304 
@@ -20,16 +20,24 @@ namespace {
20// CTRL[51] selects the mmad M/N compute-direction priority20// CTRL[51] selects the mmad M/N compute-direction priority
21static constexpr unsigned int ComputeOrderBit = 51;21static constexpr unsigned int ComputeOrderBit = 51;
22 22 
23+// CTRL[46] enables the mmad HF32 rounding mode
24+static constexpr unsigned int HF32ModeBit = 46;
25+ 
26+// CTRL[47] selects the mmad HF32 rounding mode:
27+// 0 = NEAREST_EVEN (hardware default), 1 = NEAREST_ZERO
28+static constexpr unsigned int HF32TransModeBit = 47;
29+ 
23struct LowerTlaMmadPattern : public OpRewritePattern<::tla::MmadOp> {30struct LowerTlaMmadPattern : public OpRewritePattern<::tla::MmadOp> {
24 LowerTlaMmadPattern(31 LowerTlaMmadPattern(
25 MLIRContext* ctx, DenseMap<Value, TensorDescriptor>& tensorDescriptorByValue,32 MLIRContext* ctx, DenseMap<Value, TensorDescriptor>& tensorDescriptorByValue,
26 SmallVectorImpl<Operation*>& toErase, DenseMap<Value, Value>& loweredMemrefByValue,33 SmallVectorImpl<Operation*>& toErase, DenseMap<Value, Value>& loweredMemrefByValue,
27- bool funcLevelComputeOrderSet)34+ bool funcLevelComputeOrderSet, bool funcLevelHF32Set)
28 : OpRewritePattern<::tla::MmadOp>(ctx),35 : OpRewritePattern<::tla::MmadOp>(ctx),
29 tensorDescriptorByValue(tensorDescriptorByValue),36 tensorDescriptorByValue(tensorDescriptorByValue),
30 toErase(toErase),37 toErase(toErase),
31 loweredMemrefByValue(loweredMemrefByValue),38 loweredMemrefByValue(loweredMemrefByValue),
32- funcLevelComputeOrderSet(funcLevelComputeOrderSet)39+ funcLevelComputeOrderSet(funcLevelComputeOrderSet),
40+ funcLevelHF32Set(funcLevelHF32Set)
33 {}41 {}
34 42 
35 LogicalResult matchAndRewrite(::tla::MmadOp op, PatternRewriter& rewriter) const override43 LogicalResult matchAndRewrite(::tla::MmadOp op, PatternRewriter& rewriter) const override
@@ -188,6 +196,14 @@ struct LowerTlaMmadPattern : public OpRewritePattern<::tla::MmadOp> {
188 bool isNFirst = computeOrderAttr.getValue() == ComputeOrder::N_FIRST;196 bool isNFirst = computeOrderAttr.getValue() == ComputeOrder::N_FIRST;
189 rewriter.create<hivm::SetCtrlOp>(op.getLoc(), isNFirst, ComputeOrderBit);197 rewriter.create<hivm::SetCtrlOp>(op.getLoc(), isNFirst, ComputeOrderBit);
190 }198 }
199+ if (!funcLevelHF32Set) {
200+ auto modeAttr = op->getAttrOfType<::tla::HF32ModeAttr>("hf32_mode");
201+ HF32Mode mode = modeAttr.getValue();
202+ bool enableHF32 = mode != HF32Mode::HF32_DISABLE;
203+ bool nearestZero = mode == HF32Mode::HF32_NEAREST_ZERO;
204+ rewriter.create<hivm::SetCtrlOp>(op.getLoc(), enableHF32, HF32ModeBit);
205+ rewriter.create<hivm::SetCtrlOp>(op.getLoc(), nearestZero, HF32TransModeBit);
206+ }
191 rewriter.create<func::CallOp>(op.getLoc(), callee, operands);207 rewriter.create<func::CallOp>(op.getLoc(), callee, operands);
192 toErase.push_back(op.getOperation());208 toErase.push_back(op.getOperation());
193 return success();209 return success();
@@ -198,6 +214,7 @@ private:
198 SmallVectorImpl<Operation*>& toErase;214 SmallVectorImpl<Operation*>& toErase;
199 DenseMap<Value, Value>& loweredMemrefByValue;215 DenseMap<Value, Value>& loweredMemrefByValue;
200 bool funcLevelComputeOrderSet;216 bool funcLevelComputeOrderSet;
217+ bool funcLevelHF32Set;
201};218};
202 219 
203struct LowerTlaCopyPattern : public OpRewritePattern<::tla::CopyOp> {220struct LowerTlaCopyPattern : public OpRewritePattern<::tla::CopyOp> {
@@ -531,8 +548,36 @@ public:
531 builder.create<hivm::SetCtrlOp>(funcOp.getLoc(), isNFirst, ComputeOrderBit);548 builder.create<hivm::SetCtrlOp>(funcOp.getLoc(), isNFirst, ComputeOrderBit);
532 funcLevelComputeOrderSet = true;549 funcLevelComputeOrderSet = true;
533 }550 }
551+ 
552+ // CTRL[46]/CTRL[47] (mmad HF32 rounding mode) are global and persist once
553+ // set, so when every mmad in this function agrees on hf32_mode they are set
554+ // once at the function entry. If the function mixes values the per-mmad path
555+ // in LowerTlaMmadPattern is used instead.
556+ std::optional<HF32Mode> funcLevelHF32Mode;
557+ bool HF32Conflict = false;
558+ root->walk([&](::tla::MmadOp op) {
559+ auto attr = op->getAttrOfType<::tla::HF32ModeAttr>("hf32_mode");
560+ HF32Mode mode = attr.getValue();
561+ if (funcLevelHF32Mode && *funcLevelHF32Mode != mode)
562+ HF32Conflict = true;
563+ else if (!funcLevelHF32Mode)
564+ funcLevelHF32Mode = mode;
565+ });
566+ bool funcLevelHF32Set = false;
567+ if (funcLevelHF32Mode && !HF32Conflict) {
568+ Block& entry = funcOp.getBody().front();
569+ PatternRewriter builder(funcOp.getContext());
570+ builder.setInsertionPointToStart(&entry);
571+ HF32Mode mode = *funcLevelHF32Mode;
572+ bool enableHF32 = mode != HF32Mode::HF32_DISABLE;
573+ bool nearestZero = mode == HF32Mode::HF32_NEAREST_ZERO;
574+ builder.create<hivm::SetCtrlOp>(funcOp.getLoc(), enableHF32, HF32ModeBit);
575+ builder.create<hivm::SetCtrlOp>(funcOp.getLoc(), nearestZero, HF32TransModeBit);
576+ funcLevelHF32Set = true;
577+ }
534 LowerTlaMmadPattern lowerMmad(578 LowerTlaMmadPattern lowerMmad(
535- &getContext(), tensorDescriptorByValue, toErase, lowering.loweredMemrefByValue, funcLevelComputeOrderSet);579+ &getContext(), tensorDescriptorByValue, toErase, lowering.loweredMemrefByValue, funcLevelComputeOrderSet,
580+ funcLevelHF32Set);
536 SmallVector<Operation*, 16> mmadOps;581 SmallVector<Operation*, 16> mmadOps;
537 root->walk([&](Operation* op) {582 root->walk([&](Operation* op) {
538 if (llvm::isa<::tla::MmadOp>(op))583 if (llvm::isa<::tla::MmadOp>(op))
@@ -17,6 +17,12 @@ static constexpr unsigned int MaskControlBit = 56;
17// CTRL[51] is the mmad M/N compute-direction priority bit.17// CTRL[51] is the mmad M/N compute-direction priority bit.
18static constexpr unsigned int ComputeOrderBit = 51;18static constexpr unsigned int ComputeOrderBit = 51;
19 19 
20+// CTRL[46] is the mmad HF32 rounding-mode enable bit.
21+static constexpr unsigned int HF32ModeBit = 46;
22+ 
23+// CTRL[47] is the mmad HF32 rounding-mode select bit.
24+static constexpr unsigned int HF32TransModeBit = 47;
25+ 
20class TlaPrologueEpiloguePass : public PassWrapper<TlaPrologueEpiloguePass, OperationPass<ModuleOp>> {26class TlaPrologueEpiloguePass : public PassWrapper<TlaPrologueEpiloguePass, OperationPass<ModuleOp>> {
21public:27public:
22 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TlaPrologueEpiloguePass)28 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TlaPrologueEpiloguePass)
@@ -59,10 +65,12 @@ public:
59 Operation* lastBodyOp = terminator ? terminator->getPrevNode() : nullptr;65 Operation* lastBodyOp = terminator ? terminator->getPrevNode() : nullptr;
60 if (auto barrier = llvm::dyn_cast_or_null<hivm::PipeBarrierOp>(lastBodyOp)) {66 if (auto barrier = llvm::dyn_cast_or_null<hivm::PipeBarrierOp>(lastBodyOp)) {
61 if (barrier.getPipe().getPipe() == hivm::PIPE::PIPE_ALL) {67 if (barrier.getPipe().getPipe() == hivm::PIPE::PIPE_ALL) {
62- // Already has a trailing PIPE_ALL barrier: restore CTRL[51] to the68+ // Already has a trailing PIPE_ALL barrier: restore CTRL[51] / CTRL[46] /
63- // hardware default just before it.69+ // CTRL[47] to the hardware defaults just before it.
64 builder.setInsertionPoint(barrier);70 builder.setInsertionPoint(barrier);
65 builder.create<hivm::SetCtrlOp>(loc, /*enable=*/false, ComputeOrderBit);71 builder.create<hivm::SetCtrlOp>(loc, /*enable=*/false, ComputeOrderBit);
72+ builder.create<hivm::SetCtrlOp>(loc, /*enable=*/false, HF32ModeBit);
73+ builder.create<hivm::SetCtrlOp>(loc, /*enable=*/false, HF32TransModeBit);
66 continue;74 continue;
67 }75 }
68 }76 }
@@ -71,8 +79,11 @@ public:
71 builder.setInsertionPoint(terminator);79 builder.setInsertionPoint(terminator);
72 else80 else
73 builder.setInsertionPointToEnd(&entry);81 builder.setInsertionPointToEnd(&entry);
74- // Restore CTRL[51] to the hardware default, then add the trailing barrier.82+ // Restore CTRL[51] / CTRL[46] / CTRL[47] to the hardware defaults, then add
83+ // the trailing barrier.
75 builder.create<hivm::SetCtrlOp>(loc, /*enable=*/false, ComputeOrderBit);84 builder.create<hivm::SetCtrlOp>(loc, /*enable=*/false, ComputeOrderBit);
85+ builder.create<hivm::SetCtrlOp>(loc, /*enable=*/false, HF32ModeBit);
86+ builder.create<hivm::SetCtrlOp>(loc, /*enable=*/false, HF32TransModeBit);
76 builder.create<hivm::PipeBarrierOp>(loc, pipeAll);87 builder.create<hivm::PipeBarrierOp>(loc, pipeAll);
77 }88 }
78 }89 }
@@ -42,7 +42,7 @@ Construction and views for front-end structured values such as Shape / Coord / S
42 42 
43### `make_shape`43### `make_shape`
44 44 
45-**Source:** [`catlass.core_api.make_shape`](../../catlass/core_api.py#L3505)45+**Source:** [`catlass.core_api.make_shape`](../../catlass/core_api.py#L3517)
46 46 
47Description:47Description:
48 48 
@@ -86,7 +86,7 @@ zn_shape = tla.make_shape((16, 8), (16, 4))
86 86 
87### `make_coord`87### `make_coord`
88 88 
89-**Source:** [`catlass.core_api.make_coord`](../../catlass/core_api.py#L3546)89+**Source:** [`catlass.core_api.make_coord`](../../catlass/core_api.py#L3558)
90 90 
91Description:91Description:
92 92 
@@ -117,7 +117,7 @@ coord = tla.make_coord(block_row, 0)
117 117 
118### `make_stride`118### `make_stride`
119 119 
120-**Source:** [`catlass.core_api.make_stride`](../../catlass/core_api.py#L3575)120+**Source:** [`catlass.core_api.make_stride`](../../catlass/core_api.py#L3587)
121 121 
122Description:122Description:
123 123 
@@ -179,7 +179,7 @@ nz_stride = tla.make_stride((1, 1024), (16, 256))
179 179 
180### `make_layout`180### `make_layout`
181 181 
182-**Source:** [`catlass.core_api.make_layout`](../../catlass/core_api.py#L3635)182+**Source:** [`catlass.core_api.make_layout`](../../catlass/core_api.py#L3647)
183 183 
184Description:184Description:
185 185 
@@ -242,7 +242,7 @@ zn = tla.make_layout(
242 242 
243### `tile_view`243### `tile_view`
244 244 
245-**Source:** [`catlass.core_api.tile_view`](../../catlass/core_api.py#L3804)245+**Source:** [`catlass.core_api.tile_view`](../../catlass/core_api.py#L3816)
246 246 
247Description:247Description:
248 248 
@@ -277,7 +277,7 @@ tile = tla.tile_view(
277 277 
278### `make_tensor`278### `make_tensor`
279 279 
280-**Source:** [`catlass.core_api.make_tensor`](../../catlass/core_api.py#L3851)280+**Source:** [`catlass.core_api.make_tensor`](../../catlass/core_api.py#L3863)
281 281 
282Description:282Description:
283 283 
@@ -322,7 +322,7 @@ tensor = tla.make_tensor(ptr, layout, coord=tla.make_coord(0, 0))
322 322 
323### `make_tensor_like`323### `make_tensor_like`
324 324 
325-**Source:** [`catlass.core_api.make_tensor_like`](../../catlass/core_api.py#L4046)325+**Source:** [`catlass.core_api.make_tensor_like`](../../catlass/core_api.py#L4060)
326 326 
327Description:327Description:
328 328 
@@ -356,7 +356,7 @@ dst = tla.make_tensor_like(ptr, like=src_tile, layoutTag=tla.arch.RowMajor)
356 356 
357### `make_ptr`357### `make_ptr`
358 358 
359-**Source:** [`catlass.core_api.make_ptr`](../../catlass/core_api.py#L7032)359+**Source:** [`catlass.core_api.make_ptr`](../../catlass/core_api.py#L7000)
360 360 
361Description:361Description:
362 362 
@@ -391,7 +391,7 @@ ptr = tla.make_ptr(tla.Float16, addr, mem_space=tla.AddressSpace.gm)
391 391 
392### `recast_ptr`392### `recast_ptr`
393 393 
394-**Source:** [`catlass.core_api.recast_ptr`](../../catlass/core_api.py#L7086)394+**Source:** [`catlass.core_api.recast_ptr`](../../catlass/core_api.py#L7054)
395 395 
396Description:396Description:
397 397 
@@ -427,12 +427,12 @@ Tensor copies between on-chip and global memory, and UB register load/store.
427 427 
428### `copy`428### `copy`
429 429 
430-**Source:** [`catlass.core_api.copy`](../../catlass/core_api.py#L4240)430+**Source:** [`catlass.core_api.copy`](../../catlass/core_api.py#L4250)
431 431 
432Description:432Description:
433 433 
434Copy data between tiles. The hardware path follows `src`/`dst` address spaces434Copy data between tiles. The hardware path follows `src`/`dst` address spaces
435-(vector: GM↔UB, UB→L1; cube: GM→L1, L1→L0A/L0B, L0C→GM|UB, L1→UB).435+(vector: GM↔UB, UB→L1; cube: GM→L1, L1→L0A/L0B, L0C→GM|UB|L1, L1→UB).
436Layout tags on the tiles select format conversion (for example ND→zN).436Layout tags on the tiles select format conversion (for example ND→zN).
437 437 
438Copy / tiling sizes follow each tile's logical `origin_shape`438Copy / tiling sizes follow each tile's logical `origin_shape`
@@ -592,7 +592,7 @@ Cube-side matrix multiply-accumulate (`tla.mmad`).
592 592 
593### `mmad`593### `mmad`
594 594 
595-**Source:** [`catlass.core_api.mmad`](../../catlass/core_api.py#L5176)595+**Source:** [`catlass.core_api.mmad`](../../catlass/core_api.py#L5134)
596 596 
597Description:597Description:
598 598 
@@ -601,7 +601,7 @@ Emit matrix-multiply-accumulate on TLA tiles.
601Prototype:601Prototype:
602 602 
603```python603```python
604-tla.mmad(acc: Tensor, lhs: Tensor, rhs: Tensor, init_c: bool | Bool | None = None, unit_flag: IndexLike | None = None, compute_order: ComputeOrder = ComputeOrder.M_FIRST, **extra_kwargs: object) -> None604+tla.mmad(acc: Tensor, lhs: Tensor, rhs: Tensor, init_c: bool | Bool | None = None, unit_flag: IndexLike | None = None, compute_order: ComputeOrder = ComputeOrder.M_FIRST, hf32_mode: HF32Mode = HF32Mode.HF32_DISABLE, **extra_kwargs: object) -> None
605```605```
606 606 
607Parameters:607Parameters:
@@ -614,6 +614,8 @@ Parameters:
614- `unit_flag` (`IndexLike | None`): Unit-flag control bits; defaults to `0`614- `unit_flag` (`IndexLike | None`): Unit-flag control bits; defaults to `0`
615 when omitted. Optional, default `None`.615 when omitted. Optional, default `None`.
616- `compute_order` (`ComputeOrder`): M/N compute-direction priority; default `M_FIRST`.616- `compute_order` (`ComputeOrder`): M/N compute-direction priority; default `M_FIRST`.
617+- `hf32_mode` (`HF32Mode`): HF32 rounding mode for FP32 operands in L0A/L0B
CheaterAbec
CheaterAbecCheaterAbec22 天前

中文文档也对应改一下

likedislike
init__zhb__
22 天前 评论:
618+ before the matrix multiply. Optional, default `HF32_DISABLE`.
617 619 
618Constraints:620Constraints:
619 621 
@@ -643,7 +645,7 @@ Mask creation and tail-mask updates.
643 645 
644#### `create_mask`646#### `create_mask`
645 647 
646-**Source:** [`catlass.core_api.create_mask`](../../catlass/core_api.py#L7344)648+**Source:** [`catlass.core_api.create_mask`](../../catlass/core_api.py#L7312)
647 649 
648Description:650Description:
649 651 
@@ -699,7 +701,7 @@ with tla.vec.func(mode="simd"):
699 701 
700#### `update_mask`702#### `update_mask`
701 703 
702-**Source:** [`catlass.core_api.update_mask`](../../catlass/core_api.py#L7408)704+**Source:** [`catlass.core_api.update_mask`](../../catlass/core_api.py#L7378)
703 705 
704Description:706Description:
705 707 
@@ -736,7 +738,7 @@ Element-wise arithmetic and unary math ops. `VectorSSA` overloads `+` / `-` / `*
736 738 
737#### `exp`739#### `exp`
738 740 
739-**Source:** [`catlass.core_api.exp`](../../catlass/core_api.py#L5768)741+**Source:** [`catlass.core_api.exp`](../../catlass/core_api.py#L5731)
740 742 
741Description:743Description:
742 744 
@@ -769,7 +771,7 @@ with tla.vec.func(mode="simd"):
769 771 
770#### `log`772#### `log`
771 773 
772-**Source:** [`catlass.core_api.log`](../../catlass/core_api.py#L5790)774+**Source:** [`catlass.core_api.log`](../../catlass/core_api.py#L5753)
773 775 
774Description:776Description:
775 777 
@@ -802,7 +804,7 @@ with tla.vec.func(mode="simd"):
802 804 
803#### `sqrt`805#### `sqrt`
804 806 
805-**Source:** [`catlass.core_api.sqrt`](../../catlass/core_api.py#L5812)807+**Source:** [`catlass.core_api.sqrt`](../../catlass/core_api.py#L5775)
806 808 
807Description:809Description:
808 810 
@@ -835,7 +837,7 @@ with tla.vec.func(mode="simd"):
835 837 
836#### `abs`838#### `abs`
837 839 
838-**Source:** [`catlass.core_api.abs`](../../catlass/core_api.py#L5834)840+**Source:** [`catlass.core_api.abs`](../../catlass/core_api.py#L5797)
839 841 
840Description:842Description:
841 843 
@@ -868,7 +870,7 @@ with tla.vec.func(mode="simd"):
868 870 
869#### `neg`871#### `neg`
870 872 
871-**Source:** [`catlass.core_api.neg`](../../catlass/core_api.py#L5856)873+**Source:** [`catlass.core_api.neg`](../../catlass/core_api.py#L5819)
872 874 
873Description:875Description:
874 876 
@@ -901,7 +903,7 @@ with tla.vec.func(mode="simd"):
901 903 
902#### `add`904#### `add`
903 905 
904-**Source:** [`catlass.core_api.add`](../../catlass/core_api.py#L6035)906+**Source:** [`catlass.core_api.add`](../../catlass/core_api.py#L5999)
905 907 
906Description:908Description:
907 909 
@@ -942,7 +944,7 @@ with tla.vec.func(mode="simd"):
942 944 
943#### `sub`945#### `sub`
944 946 
945-**Source:** [`catlass.core_api.sub`](../../catlass/core_api.py#L6081)947+**Source:** [`catlass.core_api.sub`](../../catlass/core_api.py#L6045)
946 948 
947Description:949Description:
948 950 
@@ -980,7 +982,7 @@ with tla.vec.func(mode="simd"):
980 982 
981#### `mul`983#### `mul`
982 984 
983-**Source:** [`catlass.core_api.mul`](../../catlass/core_api.py#L6118)985+**Source:** [`catlass.core_api.mul`](../../catlass/core_api.py#L6082)
984 986 
985Description:987Description:
986 988 
@@ -1019,7 +1021,7 @@ with tla.vec.func(mode="simd"):
1019 1021 
1020#### `max`1022#### `max`
1021 1023 
1022-**Source:** [`catlass.core_api.max`](../../catlass/core_api.py#L6163)1024+**Source:** [`catlass.core_api.max`](../../catlass/core_api.py#L6127)
1023 1025 
1024Description:1026Description:
1025 1027 
@@ -1053,7 +1055,7 @@ with tla.vec.func(mode="simd"):
1053 1055 
1054#### `min`1056#### `min`
1055 1057 
1056-**Source:** [`catlass.core_api.min`](../../catlass/core_api.py#L6203)1058+**Source:** [`catlass.core_api.min`](../../catlass/core_api.py#L6167)
1057 1059 
1058Description:1060Description:
1059 1061 
@@ -1087,7 +1089,7 @@ with tla.vec.func(mode="simd"):
1087 1089 
1088#### `div`1090#### `div`
1089 1091 
1090-**Source:** [`catlass.core_api.div`](../../catlass/core_api.py#L6243)1092+**Source:** [`catlass.core_api.div`](../../catlass/core_api.py#L6207)
1091 1093 
1092Description:1094Description:
1093 1095 
@@ -1129,7 +1131,7 @@ Bitwise and logical ops on Mask / Vector.
1129 1131 
1130#### `bitwise_not`1132#### `bitwise_not`
1131 1133 
1132-**Source:** [`catlass.core_api.bitwise_not`](../../catlass/core_api.py#L6001)1134+**Source:** [`catlass.core_api.bitwise_not`](../../catlass/core_api.py#L5965)
1133 1135 
1134Description:1136Description:
1135 1137 
@@ -1162,7 +1164,7 @@ with tla.vec.func(mode="simd"):
1162 1164 
1163#### `bitwise_and`1165#### `bitwise_and`
1164 1166 
1165-**Source:** [`catlass.core_api.bitwise_and`](../../catlass/core_api.py#L6610)1167+**Source:** [`catlass.core_api.bitwise_and`](../../catlass/core_api.py#L6576)
1166 1168 
1167Description:1169Description:
1168 1170 
@@ -1196,7 +1198,7 @@ with tla.vec.func(mode="simd"):
1196 1198 
1197#### `bitwise_or`1199#### `bitwise_or`
1198 1200 
1199-**Source:** [`catlass.core_api.bitwise_or`](../../catlass/core_api.py#L6648)1201+**Source:** [`catlass.core_api.bitwise_or`](../../catlass/core_api.py#L6614)
1200 1202 
1201Description:1203Description:
1202 1204 
@@ -1230,7 +1232,7 @@ with tla.vec.func(mode="simd"):
1230 1232 
1231#### `bitwise_xor`1233#### `bitwise_xor`
1232 1234 
1233-**Source:** [`catlass.core_api.bitwise_xor`](../../catlass/core_api.py#L6686)1235+**Source:** [`catlass.core_api.bitwise_xor`](../../catlass/core_api.py#L6652)
1234 1236 
1235Description:1237Description:
1236 1238 
@@ -1268,7 +1270,7 @@ Vector compares that produce masks, and masked select.
1268 1270 
1269#### `where`1271#### `where`
1270 1272 
1271-**Source:** [`catlass.core_api.where`](../../catlass/core_api.py#L6327)1273+**Source:** [`catlass.core_api.where`](../../catlass/core_api.py#L6291)
1272 1274 
1273Description:1275Description:
1274 1276 
@@ -1302,7 +1304,7 @@ with tla.vec.func(mode="simd"):
1302 1304 
1303#### `cmp`1305#### `cmp`
1304 1306 
1305-**Source:** [`catlass.core_api.cmp`](../../catlass/core_api.py#L6534)1307+**Source:** [`catlass.core_api.cmp`](../../catlass/core_api.py#L6498)
1306 1308 
1307Description:1309Description:
1308 1310 
@@ -1341,7 +1343,7 @@ Constant fill and lane-index sequence construction.
1341 1343 
1342#### `full`1344#### `full`
1343 1345 
1344-**Source:** [`catlass.core_api.full`](../../catlass/core_api.py#L5277)1346+**Source:** [`catlass.core_api.full`](../../catlass/core_api.py#L5243)
1345 1347 
1346Description:1348Description:
1347 1349 
@@ -1374,7 +1376,7 @@ with tla.vec.func(mode="simd"):
1374 1376 
1375#### `arange`1377#### `arange`
1376 1378 
1377-**Source:** [`catlass.core_api.arange`](../../catlass/core_api.py#L5350)1379+**Source:** [`catlass.core_api.arange`](../../catlass/core_api.py#L5316)
1378 1380 
1379Description:1381Description:
1380 1382 
@@ -1412,7 +1414,7 @@ Gather elements from a UB tensor by index.
1412 1414 
1413#### `gather`1415#### `gather`
1414 1416 
1415-**Source:** [`catlass.core_api.gather`](../../catlass/core_api.py#L6724)1417+**Source:** [`catlass.core_api.gather`](../../catlass/core_api.py#L6690)
1416 1418 
1417Description:1419Description:
1418 1420 
@@ -1450,7 +1452,7 @@ Interleave / deinterleave and related lane reshuffles.
1450 1452 
1451#### `interleave`1453#### `interleave`
1452 1454 
1453-**Source:** [`catlass.core_api.interleave`](../../catlass/core_api.py#L5894)1455+**Source:** [`catlass.core_api.interleave`](../../catlass/core_api.py#L5856)
1454 1456 
1455Description:1457Description:
1456 1458 
@@ -1483,7 +1485,7 @@ with tla.vec.func(mode="simd"):
1483 1485 
1484#### `deinterleave`1486#### `deinterleave`
1485 1487 
1486-**Source:** [`catlass.core_api.deinterleave`](../../catlass/core_api.py#L5947)1488+**Source:** [`catlass.core_api.deinterleave`](../../catlass/core_api.py#L5910)
1487 1489 
1488Description:1490Description:
1489 1491 
@@ -1520,7 +1522,7 @@ Compress valid lanes under a mask.
1520 1522 
1521#### `squeeze`1523#### `squeeze`
1522 1524 
1523-**Source:** [`catlass.core_api.squeeze`](../../catlass/core_api.py#L6381)1525+**Source:** [`catlass.core_api.squeeze`](../../catlass/core_api.py#L6345)
1524 1526 
1525Description:1527Description:
1526 1528 
@@ -1557,7 +1559,7 @@ In-core / cross-core flags, pipe barriers, mutexes, and local-memory barriers.
1557 1559 
1558### `flag`1560### `flag`
1559 1561 
1560-**Source:** [`catlass.core_api.flag`](../../catlass/core_api.py#L4473)1562+**Source:** [`catlass.core_api.flag`](../../catlass/core_api.py#L4442)
1561 1563 
1562Description:1564Description:
1563 1565 
@@ -1595,7 +1597,7 @@ with tla.vector():
1595 1597 
1596### `cross_flag`1598### `cross_flag`
1597 1599 
1598-**Source:** [`catlass.core_api.cross_flag`](../../catlass/core_api.py#L4526)1600+**Source:** [`catlass.core_api.cross_flag`](../../catlass/core_api.py#L4495)
1599 1601 
1600Description:1602Description:
1601 1603 
@@ -1627,7 +1629,7 @@ cf = tla.cross_flag("aic_aiv", mode=2)
1627 1629 
1628### `cross_core_set_flag`1630### `cross_core_set_flag`
1629 1631 
1630-**Source:** [`catlass.core_api.cross_core_set_flag`](../../catlass/core_api.py#L4602)1632+**Source:** [`catlass.core_api.cross_core_set_flag`](../../catlass/core_api.py#L4567)
1631 1633 
1632Description:1634Description:
1633 1635 
@@ -1662,7 +1664,7 @@ with tla.cube():
1662 1664 
1663### `cross_core_wait_flag`1665### `cross_core_wait_flag`
1664 1666 
1665-**Source:** [`catlass.core_api.cross_core_wait_flag`](../../catlass/core_api.py#L4646)1667+**Source:** [`catlass.core_api.cross_core_wait_flag`](../../catlass/core_api.py#L4613)
1666 1668 
1667Description:1669Description:
1668 1670 
@@ -1696,7 +1698,7 @@ with tla.vector():
1696 1698 
1697### `set_flag`1699### `set_flag`
1698 1700 
1699-**Source:** [`catlass.core_api.set_flag`](../../catlass/core_api.py#L4689)1701+**Source:** [`catlass.core_api.set_flag`](../../catlass/core_api.py#L4658)
1700 1702 
1701Description:1703Description:
1702 1704 
@@ -1728,7 +1730,7 @@ with tla.vector():
1728 1730 
1729### `wait_flag`1731### `wait_flag`
1730 1732 
1731-**Source:** [`catlass.core_api.wait_flag`](../../catlass/core_api.py#L4715)1733+**Source:** [`catlass.core_api.wait_flag`](../../catlass/core_api.py#L4684)
1732 1734 
1733Description:1735Description:
1734 1736 
@@ -1760,7 +1762,7 @@ with tla.vector():
1760 1762 
1761### `pipe_barrier`1763### `pipe_barrier`
1762 1764 
1763-**Source:** [`catlass.core_api.pipe_barrier`](../../catlass/core_api.py#L4741)1765+**Source:** [`catlass.core_api.pipe_barrier`](../../catlass/core_api.py#L4710)
1764 1766 
1765Description:1767Description:
1766 1768 
@@ -1792,7 +1794,7 @@ with tla.vector():
1792 1794 
1793### `mutex`1795### `mutex`
1794 1796 
1795-**Source:** [`catlass.core_api.mutex`](../../catlass/core_api.py#L4784)1797+**Source:** [`catlass.core_api.mutex`](../../catlass/core_api.py#L4745)
1796 1798 
1797Description:1799Description:
1798 1800 
@@ -1824,7 +1826,7 @@ mtx = tla.mutex("l1_buf", id=0)
1824 1826 
1825### `mutex_guard`1827### `mutex_guard`
1826 1828 
1827-**Source:** [`catlass.core_api.mutex_guard`](../../catlass/core_api.py#L4832)1829+**Source:** [`catlass.core_api.mutex_guard`](../../catlass/core_api.py#L4793)
1828 1830 
1829Description:1831Description:
1830 1832 
@@ -1856,7 +1858,7 @@ with tla.mutex_guard(mtx):
1856 1858 
1857### `mutex_lock`1859### `mutex_lock`
1858 1860 
1859-**Source:** [`catlass.core_api.mutex_lock`](../../catlass/core_api.py#L4873)1861+**Source:** [`catlass.core_api.mutex_lock`](../../catlass/core_api.py#L4834)
1860 1862 
1861Description:1863Description:
1862 1864 
@@ -1888,7 +1890,7 @@ tla.mutex_lock(mtx, pipe=tla.arch.MTE2)
1888 1890 
1889### `mutex_unlock`1891### `mutex_unlock`
1890 1892 
1891-**Source:** [`catlass.core_api.mutex_unlock`](../../catlass/core_api.py#L4903)1893+**Source:** [`catlass.core_api.mutex_unlock`](../../catlass/core_api.py#L4864)
1892 1894 
1893Description:1895Description:
1894 1896 
@@ -1920,7 +1922,7 @@ tla.mutex_unlock(mtx, pipe=tla.arch.MTE2)
1920 1922 
1921### `local_mem_bar`1923### `local_mem_bar`
1922 1924 
1923-**Source:** [`catlass.core_api.local_mem_bar`](../../catlass/core_api.py#L4933)1925+**Source:** [`catlass.core_api.local_mem_bar`](../../catlass/core_api.py#L4893)
1924 1926 
1925Description:1927Description:
1926 1928 
@@ -1957,7 +1959,7 @@ Architecture attributes on `tla.arch` (layout tags, pipe identifiers, block help
1957 1959 
1958### `arch`1960### `arch`
1959 1961 
1960-**Source:** [`catlass.core_api.arch`](../../catlass/core_api.py#L7202)1962+**Source:** [`catlass.core_api.arch`](../../catlass/core_api.py#L7170)
1961 1963 
1962Description:1964Description:
1963 1965 
@@ -2028,7 +2030,7 @@ On-chip scratch allocation via `allocate`.
2028 2030 
2029### `allocate`2031### `allocate`
2030 2032 
2031-**Source:** [`catlass.core_api.allocate`](../../catlass/core_api.py#L6972)2033+**Source:** [`catlass.core_api.allocate`](../../catlass/core_api.py#L6938)
2032 2034 
2033Description:2035Description:
2034 2036 
@@ -2071,7 +2073,7 @@ In-kernel scalar / tensor debug printing.
2071 2073 
2072### `print`2074### `print`
2073 2075 
2074-**Source:** [`catlass.core_api.print`](../../catlass/core_api.py#L3345)2076+**Source:** [`catlass.core_api.print`](../../catlass/core_api.py#L3355)
2075 2077 
2076Description:2078Description:
2077 2079 
@@ -2109,7 +2111,7 @@ Cube / Vector / `vec.func` regions and kernel-side loop ranges.
2109 2111 
2110### `range`2112### `range`
2111 2113 
2112-**Source:** [`catlass.core_api.range`](../../catlass/core_api.py#L4985)2114+**Source:** [`catlass.core_api.range`](../../catlass/core_api.py#L4943)
2113 2115 
2114Description:2116Description:
2115 2117 
@@ -2143,7 +2145,7 @@ for i in tla.range(0, n, 1):
2143 2145 
2144### `range_constexpr`2146### `range_constexpr`
2145 2147 
2146-**Source:** [`catlass.core_api.range_constexpr`](../../catlass/core_api.py#L5035)2148+**Source:** [`catlass.core_api.range_constexpr`](../../catlass/core_api.py#L4993)
2147 2149 
2148Description:2150Description:
2149 2151 
@@ -2177,7 +2179,7 @@ for k in tla.range_constexpr(0, 4):
2177 2179 
2178### `cube`2180### `cube`
2179 2181 
2180-**Source:** [`catlass.core_api.cube`](../../catlass/core_api.py#L5081)2182+**Source:** [`catlass.core_api.cube`](../../catlass/core_api.py#L5039)
2181 2183 
2182Description:2184Description:
2183 2185 
@@ -2209,7 +2211,7 @@ with tla.cube():
2209 2211 
2210### `vector`2212### `vector`
2211 2213 
2212-**Source:** [`catlass.core_api.vector`](../../catlass/core_api.py#L5103)2214+**Source:** [`catlass.core_api.vector`](../../catlass/core_api.py#L5061)
2213 2215 
2214Description:2216Description:
2215 2217 
@@ -2241,7 +2243,7 @@ with tla.vector():
2241 2243 
2242### `vec.func`2244### `vec.func`
2243 2245 
2244-**Source:** [`catlass.core_api._vec_func`](../../catlass/core_api.py#L5137)2246+**Source:** [`catlass.core_api._vec_func`](../../catlass/core_api.py#L5095)
2245 2247 
2246Description:2248Description:
2247 2249 
@@ -46,7 +46,7 @@ Shape / Coord / Stride / Layout / Tensor 等前端结构化值的构造与视图
46### `make_shape`46### `make_shape`
47 47 
48 48 
49-**源码:** [`catlass.core_api.make_shape`](../../catlass/core_api.py#L3516)49+**源码:** [`catlass.core_api.make_shape`](../../catlass/core_api.py#L3517)
50 50 
51功能说明:51功能说明:
52 52 
@@ -93,7 +93,7 @@ zn_shape = tla.make_shape((16, 8), (16, 4))
93### `make_coord`93### `make_coord`
94 94 
95 95 
96-**源码:** [`catlass.core_api.make_coord`](../../catlass/core_api.py#L3557)96+**源码:** [`catlass.core_api.make_coord`](../../catlass/core_api.py#L3558)
97 97 
98功能说明:98功能说明:
99 99 
@@ -129,7 +129,7 @@ coord = tla.make_coord(block_row, 0)
129### `make_stride`129### `make_stride`
130 130 
131 131 
132-**源码:** [`catlass.core_api.make_stride`](../../catlass/core_api.py#L3586)132+**源码:** [`catlass.core_api.make_stride`](../../catlass/core_api.py#L3587)
133 133 
134功能说明:134功能说明:
135 135 
@@ -195,7 +195,7 @@ nz_stride = tla.make_stride((1, 1024), (16, 256))
195### `make_layout`195### `make_layout`
196 196 
197 197 
198-**源码:** [`catlass.core_api.make_layout`](../../catlass/core_api.py#L3646)198+**源码:** [`catlass.core_api.make_layout`](../../catlass/core_api.py#L3647)
199 199 
200功能说明:200功能说明:
201 201 
@@ -260,7 +260,7 @@ zn = tla.make_layout(
260### `tile_view`260### `tile_view`
261 261 
262 262 
263-**源码:** [`catlass.core_api.tile_view`](../../catlass/core_api.py#L3815)263+**源码:** [`catlass.core_api.tile_view`](../../catlass/core_api.py#L3816)
264 264 
265功能说明:265功能说明:
266 266 
@@ -300,7 +300,7 @@ tile = tla.tile_view(
300### `make_tensor`300### `make_tensor`
301 301 
302 302 
303-**源码:** [`catlass.core_api.make_tensor`](../../catlass/core_api.py#L3862)303+**源码:** [`catlass.core_api.make_tensor`](../../catlass/core_api.py#L3863)
304 304 
305功能说明:305功能说明:
306 306 
@@ -344,7 +344,7 @@ tensor = tla.make_tensor(ptr, layout, coord=tla.make_coord(0, 0))
344### `make_tensor_like`344### `make_tensor_like`
345 345 
346 346 
347-**源码:** [`catlass.core_api.make_tensor_like`](../../catlass/core_api.py#L4059)347+**源码:** [`catlass.core_api.make_tensor_like`](../../catlass/core_api.py#L4060)
348 348 
349功能说明:349功能说明:
350 350 
@@ -383,7 +383,7 @@ dst = tla.make_tensor_like(ptr, like=src_tile, layoutTag=tla.arch.RowMajor)
383### `make_ptr`383### `make_ptr`
384 384 
385 385 
386-**源码:** [`catlass.core_api.make_ptr`](../../catlass/core_api.py#L6968)386+**源码:** [`catlass.core_api.make_ptr`](../../catlass/core_api.py#L7000)
387 387 
388功能说明:388功能说明:
389 389 
@@ -422,7 +422,7 @@ ptr = tla.make_ptr(tla.Float16, addr, mem_space=tla.AddressSpace.gm)
422### `recast_ptr`422### `recast_ptr`
423 423 
424 424 
425-**源码:** [`catlass.core_api.recast_ptr`](../../catlass/core_api.py#L7022)425+**源码:** [`catlass.core_api.recast_ptr`](../../catlass/core_api.py#L7054)
426 426 
427功能说明:427功能说明:
428 428 
@@ -462,7 +462,7 @@ ptr_f32 = tla.recast_ptr(ptr_f16, dtype=tla.Float32)
462### `copy`462### `copy`
463 463 
464 464 
465-**源码:** [`catlass.core_api.copy`](../../catlass/core_api.py#L4249)465+**源码:** [`catlass.core_api.copy`](../../catlass/core_api.py#L4250)
466 466 
467功能说明:467功能说明:
468 468 
@@ -550,7 +550,7 @@ with tla.cube():
550### `Tensor.load`550### `Tensor.load`
551 551 
552 552 
553-**源码:** [`catlass.tla.tensor._Tensor.load`](../../catlass/tla/tensor.py#L211)553+**源码:** [`catlass.tla.tensor._Tensor.load`](../../catlass/tla/tensor.py#L215)
554 554 
555功能说明:555功能说明:
556 556 
@@ -589,7 +589,7 @@ with tla.vec.func(mode="simd"):
589### `Tensor.store`589### `Tensor.store`
590 590 
591 591 
592-**源码:** [`catlass.tla.tensor._Tensor.store`](../../catlass/tla/tensor.py#L382)592+**源码:** [`catlass.tla.tensor._Tensor.store`](../../catlass/tla/tensor.py#L383)
593 593 
594功能说明:594功能说明:
595 595 
@@ -631,7 +631,7 @@ Cube 侧矩阵乘加(`tla.mmad`)。
631### `mmad`631### `mmad`
632 632 
633 633 
634-**源码:** [`catlass.core_api.mmad`](../../catlass/core_api.py#L5140)634+**源码:** [`catlass.core_api.mmad`](../../catlass/core_api.py#L5134)
635 635 
636功能说明:636功能说明:
637 637 
@@ -640,7 +640,7 @@ Cube 侧矩阵乘加(`tla.mmad`)。
640函数原型:640函数原型:
641 641 
642```python642```python
643-tla.mmad(acc: Tensor, lhs: Tensor, rhs: Tensor, init_c: bool | Bool | None = None, unit_flag: IndexLike | None = None, compute_order: ComputeOrder = ComputeOrder.M_FIRST, **extra_kwargs: object) -> None643+tla.mmad(acc: Tensor, lhs: Tensor, rhs: Tensor, init_c: bool | Bool | None = None, unit_flag: IndexLike | None = None, compute_order: ComputeOrder = ComputeOrder.M_FIRST, hf32_mode: HF32Mode = HF32Mode.HF32_DISABLE, **extra_kwargs: object) -> None
644```644```
645 645 
646参数说明:646参数说明:
@@ -651,6 +651,7 @@ tla.mmad(acc: Tensor, lhs: Tensor, rhs: Tensor, init_c: bool | Bool | None = Non
651- `init_c``bool | Bool | None`):是否先清零累加器;省略时默认为 `False`。可选,默认 `None`651- `init_c``bool | Bool | None`):是否先清零累加器;省略时默认为 `False`。可选,默认 `None`
652- `unit_flag``IndexLike | None`):unit flag 控制位;省略时默认为 `0`。可选,默认 `None`652- `unit_flag``IndexLike | None`):unit flag 控制位;省略时默认为 `0`。可选,默认 `None`
653- `compute_order``ComputeOrder`):M/N 计算方向优先级;默认 `M_FIRST`653- `compute_order``ComputeOrder`):M/N 计算方向优先级;默认 `M_FIRST`
654+- `hf32_mode``HF32Mode`):FP32 操作数在 L0A/L0B 上、矩阵乘之前的 HF32 舍入模式。可选,默认 `HF32_DISABLE`
654 655 
655约束说明:656约束说明:
656 657 
@@ -683,7 +684,7 @@ Mask 创建与尾块更新。
683#### `create_mask`684#### `create_mask`
684 685 
685 686 
686-**源码:** [`catlass.core_api.create_mask`](../../catlass/core_api.py#L7280)687+**源码:** [`catlass.core_api.create_mask`](../../catlass/core_api.py#L7312)
687 688 
688功能说明:689功能说明:
689 690 
@@ -743,7 +744,7 @@ with tla.vec.func(mode="simd"):
743#### `update_mask`744#### `update_mask`
744 745 
745 746 
746-**源码:** [`catlass.core_api.update_mask`](../../catlass/core_api.py#L7346)747+**源码:** [`catlass.core_api.update_mask`](../../catlass/core_api.py#L7378)
747 748 
748功能说明:749功能说明:
749 750 
@@ -783,7 +784,7 @@ with tla.vec.func(mode="simd"):
783#### `exp`784#### `exp`
784 785 
785 786 
786-**源码:** [`catlass.core_api.exp`](../../catlass/core_api.py#L5723)787+**源码:** [`catlass.core_api.exp`](../../catlass/core_api.py#L5731)
787 788 
788功能说明:789功能说明:
789 790 
@@ -821,7 +822,7 @@ with tla.vec.func(mode="simd"):
821#### `log`822#### `log`
822 823 
823 824 
824-**源码:** [`catlass.core_api.log`](../../catlass/core_api.py#L5745)825+**源码:** [`catlass.core_api.log`](../../catlass/core_api.py#L5753)
825 826 
826功能说明:827功能说明:
827 828 
@@ -859,7 +860,7 @@ with tla.vec.func(mode="simd"):
859#### `sqrt`860#### `sqrt`
860 861 
861 862 
862-**源码:** [`catlass.core_api.sqrt`](../../catlass/core_api.py#L5767)863+**源码:** [`catlass.core_api.sqrt`](../../catlass/core_api.py#L5775)
863 864 
864功能说明:865功能说明:
865 866 
@@ -897,7 +898,7 @@ with tla.vec.func(mode="simd"):
897#### `abs`898#### `abs`
898 899 
899 900 
900-**源码:** [`catlass.core_api.abs`](../../catlass/core_api.py#L5789)901+**源码:** [`catlass.core_api.abs`](../../catlass/core_api.py#L5797)
901 902 
902功能说明:903功能说明:
903 904 
@@ -935,7 +936,7 @@ with tla.vec.func(mode="simd"):
935#### `neg`936#### `neg`
936 937 
937 938 
938-**源码:** [`catlass.core_api.neg`](../../catlass/core_api.py#L5811)939+**源码:** [`catlass.core_api.neg`](../../catlass/core_api.py#L5819)
939 940 
940功能说明:941功能说明:
941 942 
@@ -973,7 +974,7 @@ with tla.vec.func(mode="simd"):
973#### `add`974#### `add`
974 975 
975 976 
976-**源码:** [`catlass.core_api.add`](../../catlass/core_api.py#L5991)977+**源码:** [`catlass.core_api.add`](../../catlass/core_api.py#L5999)
977 978 
978功能说明:979功能说明:
979 980 
@@ -1019,7 +1020,7 @@ with tla.vec.func(mode="simd"):
1019#### `sub`1020#### `sub`
1020 1021 
1021 1022 
1022-**源码:** [`catlass.core_api.sub`](../../catlass/core_api.py#L6037)1023+**源码:** [`catlass.core_api.sub`](../../catlass/core_api.py#L6045)
1023 1024 
1024功能说明:1025功能说明:
1025 1026 
@@ -1062,7 +1063,7 @@ with tla.vec.func(mode="simd"):
1062#### `mul`1063#### `mul`
1063 1064 
1064 1065 
1065-**源码:** [`catlass.core_api.mul`](../../catlass/core_api.py#L6074)1066+**源码:** [`catlass.core_api.mul`](../../catlass/core_api.py#L6082)
1066 1067 
1067功能说明:1068功能说明:
1068 1069 
@@ -1106,7 +1107,7 @@ with tla.vec.func(mode="simd"):
1106#### `max`1107#### `max`
1107 1108 
1108 1109 
1109-**源码:** [`catlass.core_api.max`](../../catlass/core_api.py#L6119)1110+**源码:** [`catlass.core_api.max`](../../catlass/core_api.py#L6127)
1110 1111 
1111功能说明:1112功能说明:
1112 1113 
@@ -1145,7 +1146,7 @@ with tla.vec.func(mode="simd"):
1145#### `min`1146#### `min`
1146 1147 
1147 1148 
1148-**源码:** [`catlass.core_api.min`](../../catlass/core_api.py#L6159)1149+**源码:** [`catlass.core_api.min`](../../catlass/core_api.py#L6167)
1149 1150 
1150功能说明:1151功能说明:
1151 1152 
@@ -1184,7 +1185,7 @@ with tla.vec.func(mode="simd"):
1184#### `div`1185#### `div`
1185 1186 
1186 1187 
1187-**源码:** [`catlass.core_api.div`](../../catlass/core_api.py#L6199)1188+**源码:** [`catlass.core_api.div`](../../catlass/core_api.py#L6207)
1188 1189 
1189功能说明:1190功能说明:
1190 1191 
@@ -1229,7 +1230,7 @@ with tla.vec.func(mode="simd"):
1229#### `bitwise_not`1230#### `bitwise_not`
1230 1231 
1231 1232 
1232-**源码:** [`catlass.core_api.bitwise_not`](../../catlass/core_api.py#L5957)1233+**源码:** [`catlass.core_api.bitwise_not`](../../catlass/core_api.py#L5965)
1233 1234 
1234功能说明:1235功能说明:
1235 1236 
@@ -1267,7 +1268,7 @@ with tla.vec.func(mode="simd"):
1267#### `bitwise_and`1268#### `bitwise_and`
1268 1269 
1269 1270 
1270-**源码:** [`catlass.core_api.bitwise_and`](../../catlass/core_api.py#L6568)1271+**源码:** [`catlass.core_api.bitwise_and`](../../catlass/core_api.py#L6576)
1271 1272 
1272功能说明:1273功能说明:
1273 1274 
@@ -1306,7 +1307,7 @@ with tla.vec.func(mode="simd"):
1306#### `bitwise_or`1307#### `bitwise_or`
1307 1308 
1308 1309 
1309-**源码:** [`catlass.core_api.bitwise_or`](../../catlass/core_api.py#L6606)1310+**源码:** [`catlass.core_api.bitwise_or`](../../catlass/core_api.py#L6614)
1310 1311 
1311功能说明:1312功能说明:
1312 1313 
@@ -1345,7 +1346,7 @@ with tla.vec.func(mode="simd"):
1345#### `bitwise_xor`1346#### `bitwise_xor`
1346 1347 
1347 1348 
1348-**源码:** [`catlass.core_api.bitwise_xor`](../../catlass/core_api.py#L6644)1349+**源码:** [`catlass.core_api.bitwise_xor`](../../catlass/core_api.py#L6652)
1349 1350 
1350功能说明:1351功能说明:
1351 1352 
@@ -1386,7 +1387,7 @@ with tla.vec.func(mode="simd"):
1386#### `where`1387#### `where`
1387 1388 
1388 1389 
1389-**源码:** [`catlass.core_api.where`](../../catlass/core_api.py#L6283)1390+**源码:** [`catlass.core_api.where`](../../catlass/core_api.py#L6291)
1390 1391 
1391功能说明:1392功能说明:
1392 1393 
@@ -1425,7 +1426,7 @@ with tla.vec.func(mode="simd"):
1425#### `cmp`1426#### `cmp`
1426 1427 
1427 1428 
1428-**源码:** [`catlass.core_api.cmp`](../../catlass/core_api.py#L6490)1429+**源码:** [`catlass.core_api.cmp`](../../catlass/core_api.py#L6498)
1429 1430 
1430功能说明:1431功能说明:
1431 1432 
@@ -1467,7 +1468,7 @@ with tla.vec.func(mode="simd"):
1467#### `full`1468#### `full`
1468 1469 
1469 1470 
1470-**源码:** [`catlass.core_api.full`](../../catlass/core_api.py#L5235)1471+**源码:** [`catlass.core_api.full`](../../catlass/core_api.py#L5243)
1471 1472 
1472功能说明:1473功能说明:
1473 1474 
@@ -1505,7 +1506,7 @@ with tla.vec.func(mode="simd"):
1505#### `arange`1506#### `arange`
1506 1507 
1507 1508 
1508-**源码:** [`catlass.core_api.arange`](../../catlass/core_api.py#L5308)1509+**源码:** [`catlass.core_api.arange`](../../catlass/core_api.py#L5316)
1509 1510 
1510功能说明:1511功能说明:
1511 1512 
@@ -1546,7 +1547,7 @@ with tla.vec.func(mode="simd"):
1546#### `gather`1547#### `gather`
1547 1548 
1548 1549 
1549-**源码:** [`catlass.core_api.gather`](../../catlass/core_api.py#L6682)1550+**源码:** [`catlass.core_api.gather`](../../catlass/core_api.py#L6690)
1550 1551 
1551功能说明:1552功能说明:
1552 1553 
@@ -1587,7 +1588,7 @@ with tla.vec.func(mode="simd"):
1587#### `interleave`1588#### `interleave`
1588 1589 
1589 1590 
1590-**源码:** [`catlass.core_api.interleave`](../../catlass/core_api.py#L5848)1591+**源码:** [`catlass.core_api.interleave`](../../catlass/core_api.py#L5856)
1591 1592 
1592功能说明:1593功能说明:
1593 1594 
@@ -1625,7 +1626,7 @@ with tla.vec.func(mode="simd"):
1625#### `deinterleave`1626#### `deinterleave`
1626 1627 
1627 1628 
1628-**源码:** [`catlass.core_api.deinterleave`](../../catlass/core_api.py#L5902)1629+**源码:** [`catlass.core_api.deinterleave`](../../catlass/core_api.py#L5910)
1629 1630 
1630功能说明:1631功能说明:
1631 1632 
@@ -1665,7 +1666,7 @@ with tla.vec.func(mode="simd"):
1665#### `squeeze`1666#### `squeeze`
1666 1667 
1667 1668 
1668-**源码:** [`catlass.core_api.squeeze`](../../catlass/core_api.py#L6337)1669+**源码:** [`catlass.core_api.squeeze`](../../catlass/core_api.py#L6345)
1669 1670 
1670功能说明:1671功能说明:
1671 1672 
@@ -1706,7 +1707,7 @@ with tla.vec.func(mode="simd"):
1706### `flag`1707### `flag`
1707 1708 
1708 1709 
1709-**源码:** [`catlass.core_api.flag`](../../catlass/core_api.py#L4430)1710+**源码:** [`catlass.core_api.flag`](../../catlass/core_api.py#L4442)
1710 1711 
1711功能说明:1712功能说明:
1712 1713 
@@ -1749,7 +1750,7 @@ with tla.vector():
1749### `cross_flag`1750### `cross_flag`
1750 1751 
1751 1752 
1752-**源码:** [`catlass.core_api.cross_flag`](../../catlass/core_api.py#L4501)1753+**源码:** [`catlass.core_api.cross_flag`](../../catlass/core_api.py#L4495)
1753 1754 
1754功能说明:1755功能说明:
1755 1756 
@@ -1786,7 +1787,7 @@ cf = tla.cross_flag("aic_aiv", mode=2)
1786### `cross_core_set_flag`1787### `cross_core_set_flag`
1787 1788 
1788 1789 
1789-**源码:** [`catlass.core_api.cross_core_set_flag`](../../catlass/core_api.py#L4573)1790+**源码:** [`catlass.core_api.cross_core_set_flag`](../../catlass/core_api.py#L4567)
1790 1791 
1791功能说明:1792功能说明:
1792 1793 
@@ -1826,7 +1827,7 @@ with tla.cube():
1826### `cross_core_wait_flag`1827### `cross_core_wait_flag`
1827 1828 
1828 1829 
1829-**源码:** [`catlass.core_api.cross_core_wait_flag`](../../catlass/core_api.py#L4619)1830+**源码:** [`catlass.core_api.cross_core_wait_flag`](../../catlass/core_api.py#L4613)
1830 1831 
1831功能说明:1832功能说明:
1832 1833 
@@ -1865,7 +1866,7 @@ with tla.vector():
1865### `set_flag`1866### `set_flag`
1866 1867 
1867 1868 
1868-**源码:** [`catlass.core_api.set_flag`](../../catlass/core_api.py#L4664)1869+**源码:** [`catlass.core_api.set_flag`](../../catlass/core_api.py#L4658)
1869 1870 
1870功能说明:1871功能说明:
1871 1872 
@@ -1902,7 +1903,7 @@ with tla.vector():
1902### `wait_flag`1903### `wait_flag`
1903 1904 
1904 1905 
1905-**源码:** [`catlass.core_api.wait_flag`](../../catlass/core_api.py#L4690)1906+**源码:** [`catlass.core_api.wait_flag`](../../catlass/core_api.py#L4684)
1906 1907 
1907功能说明:1908功能说明:
1908 1909 
@@ -1939,7 +1940,7 @@ with tla.vector():
1939### `pipe_barrier`1940### `pipe_barrier`
1940 1941 
1941 1942 
1942-**源码:** [`catlass.core_api.pipe_barrier`](../../catlass/core_api.py#L4716)1943+**源码:** [`catlass.core_api.pipe_barrier`](../../catlass/core_api.py#L4710)
1943 1944 
1944功能说明:1945功能说明:
1945 1946 
@@ -1976,7 +1977,7 @@ with tla.vector():
1976### `mutex`1977### `mutex`
1977 1978 
1978 1979 
1979-**源码:** [`catlass.core_api.mutex`](../../catlass/core_api.py#L4751)1980+**源码:** [`catlass.core_api.mutex`](../../catlass/core_api.py#L4745)
1980 1981 
1981功能说明:1982功能说明:
1982 1983 
@@ -2013,7 +2014,7 @@ mtx = tla.mutex("l1_buf", id=0)
2013### `mutex_guard`2014### `mutex_guard`
2014 2015 
2015 2016 
2016-**源码:** [`catlass.core_api.mutex_guard`](../../catlass/core_api.py#L4799)2017+**源码:** [`catlass.core_api.mutex_guard`](../../catlass/core_api.py#L4793)
2017 2018 
2018功能说明:2019功能说明:
2019 2020 
@@ -2050,7 +2051,7 @@ with tla.mutex_guard(mtx):
2050### `mutex_lock`2051### `mutex_lock`
2051 2052 
2052 2053 
2053-**源码:** [`catlass.core_api.mutex_lock`](../../catlass/core_api.py#L4840)2054+**源码:** [`catlass.core_api.mutex_lock`](../../catlass/core_api.py#L4834)
2054 2055 
2055功能说明:2056功能说明:
2056 2057 
@@ -2087,7 +2088,7 @@ tla.mutex_lock(mtx, pipe=tla.arch.MTE2)
2087### `mutex_unlock`2088### `mutex_unlock`
2088 2089 
2089 2090 
2090-**源码:** [`catlass.core_api.mutex_unlock`](../../catlass/core_api.py#L4870)2091+**源码:** [`catlass.core_api.mutex_unlock`](../../catlass/core_api.py#L4864)
2091 2092 
2092功能说明:2093功能说明:
2093 2094 
@@ -2124,7 +2125,7 @@ tla.mutex_unlock(mtx, pipe=tla.arch.MTE2)
2124### `local_mem_bar`2125### `local_mem_bar`
2125 2126 
2126 2127 
2127-**源码:** [`catlass.core_api.local_mem_bar`](../../catlass/core_api.py#L4899)2128+**源码:** [`catlass.core_api.local_mem_bar`](../../catlass/core_api.py#L4893)
2128 2129 
2129功能说明:2130功能说明:
2130 2131 
@@ -2165,7 +2166,7 @@ with tla.vec.func(mode="simd"):
2165### `arch`2166### `arch`
2166 2167 
2167 2168 
2168-**源码:** [`catlass.core_api.arch`](../../catlass/core_api.py#L7138)2169+**源码:** [`catlass.core_api.arch`](../../catlass/core_api.py#L7170)
2169 2170 
2170功能说明:2171功能说明:
2171 2172 
@@ -2235,7 +2236,7 @@ ub_bytes = tla.arch.get_capacity_in_bytes(tla.arch.UB)
2235### `allocate`2236### `allocate`
2236 2237 
2237 2238 
2238-**源码:** [`catlass.core_api.allocate`](../../catlass/core_api.py#L6906)2239+**源码:** [`catlass.core_api.allocate`](../../catlass/core_api.py#L6938)
2239 2240 
2240功能说明:2241功能说明:
2241 2242 
@@ -2282,7 +2283,7 @@ kernel 内标量 / tensor 调试打印。
2282### `print`2283### `print`
2283 2284 
2284 2285 
2285-**源码:** [`catlass.core_api.print`](../../catlass/core_api.py#L3354)2286+**源码:** [`catlass.core_api.print`](../../catlass/core_api.py#L3355)
2286 2287 
2287功能说明:2288功能说明:
2288 2289 
@@ -2325,7 +2326,7 @@ Cube / Vector / `vec.func` 区域以及 kernel 侧循环范围。
2325### `range`2326### `range`
2326 2327 
2327 2328 
2328-**源码:** [`catlass.core_api.range`](../../catlass/core_api.py#L4949)2329+**源码:** [`catlass.core_api.range`](../../catlass/core_api.py#L4943)
2329 2330 
2330功能说明:2331功能说明:
2331 2332 
@@ -2366,7 +2367,7 @@ for i in tla.range(0, n, 1):
2366### `range_constexpr`2367### `range_constexpr`
2367 2368 
2368 2369 
2369-**源码:** [`catlass.core_api.range_constexpr`](../../catlass/core_api.py#L4999)2370+**源码:** [`catlass.core_api.range_constexpr`](../../catlass/core_api.py#L4993)
2370 2371 
2371功能说明:2372功能说明:
2372 2373 
@@ -2407,7 +2408,7 @@ for k in tla.range_constexpr(0, 4):
2407### `cube`2408### `cube`
2408 2409 
2409 2410 
2410-**源码:** [`catlass.core_api.cube`](../../catlass/core_api.py#L5045)2411+**源码:** [`catlass.core_api.cube`](../../catlass/core_api.py#L5039)
2411 2412 
2412功能说明:2413功能说明:
2413 2414 
@@ -2446,7 +2447,7 @@ with tla.cube():
2446### `vector`2447### `vector`
2447 2448 
2448 2449 
2449-**源码:** [`catlass.core_api.vector`](../../catlass/core_api.py#L5067)2450+**源码:** [`catlass.core_api.vector`](../../catlass/core_api.py#L5061)
2450 2451 
2451功能说明:2452功能说明:
2452 2453 
@@ -2485,7 +2486,7 @@ with tla.vector():
2485### `vec.func`2486### `vec.func`
2486 2487 
2487 2488 
2488-**源码:** [`catlass.core_api._vec_func`](../../catlass/core_api.py#L5101)2489+**源码:** [`catlass.core_api._vec_func`](../../catlass/core_api.py#L5095)
2489 2490 
2490功能说明:2491功能说明:
2491 2492 
@@ -70,8 +70,8 @@ basic_mixed.py [-h] [--device DEVICE] [--m M] [--n N] [--k K]
70| `--device` | `0` | 上板执行使用的 NPU 设备号。 |70| `--device` | `0` | 上板执行使用的 NPU 设备号。 |
71| `--m` / `--n` / `--k` | `32`, `32`, `32` | 矩阵乘加的问题大小 |71| `--m` / `--n` / `--k` | `32`, `32`, `32` | 矩阵乘加的问题大小 |
72| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"``"col"`,表示行优先或列优先布局。 |72| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"``"col"`,表示行优先或列优先布局。 |
73-| `--block-num` | `-1`(依据所使用的 NPU 设备采集其满核值) | 启用的 AI Core 核数 |73+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
74-| `--sentinel` | `-9.0` | Kernel 启动前入结果 C 哨兵值。 |74+| `--sentinel` | `-9.0` | Kernel 启动前预先填入结果矩阵的值。 |
75 75 
76### 执行示例76### 执行示例
77 77 
@@ -74,7 +74,7 @@ basic_matmul.py [-h] [--device DEVICE] [--m M] [--n N] [--k K]
74| `--k` | `1024` | 矩阵乘累加轴的大小 |74| `--k` | `1024` | 矩阵乘累加轴的大小 |
75| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"``"col"`,表示行优先或列优先布局。 |75| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"``"col"`,表示行优先或列优先布局。 |
76| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围包括`"f16"`, `"bf16"``"f32"` 。 |76| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围包括`"f16"`, `"bf16"``"f32"` 。 |
77-| `--block-num` | `-1`(依据所使用的 NPU 设备采集其满核值) | 启用的 AI Core 核数 |77+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
78 78 
79### 执行示例79### 执行示例
80 80 
@@ -39,6 +39,7 @@ def basic_mmad_kernel(
39 gm_b: tla.Tensor,39 gm_b: tla.Tensor,
40 gm_c: tla.Tensor,40 gm_c: tla.Tensor,
41 _tiling: TilingParams,41 _tiling: TilingParams,
42+ hf32_mode: tla.Constexpr[tla.params.HF32Mode],
42) -> None:43) -> None:
43 c0 = 044 c0 = 0
44 c1 = 145 c1 = 1
@@ -239,7 +240,21 @@ def basic_mmad_kernel(
239 else 0b10240 else 0b10
240 )241 )
241 init_c = True if k_l1 == 0 and k_l0 == 0 else False242 init_c = True if k_l1 == 0 and k_l0 == 0 else False
242- tla.mmad(l0_c, l0_a, l0_b, init_c=init_c, unit_flag=unit_flag)243+ if tla.const_expr(
244+ hf32_mode != tla.params.HF32Mode.HF32_DISABLE
245+ and dtype_a == tla.Float32
246+ and dtype_b == tla.Float32
247+ ):
248+ tla.mmad(
249+ l0_c,
250+ l0_a,
251+ l0_b,
252+ init_c=init_c,
253+ unit_flag=unit_flag,
254+ hf32_mode=hf32_mode,
255+ )
256+ else:
257+ tla.mmad(l0_c, l0_a, l0_b, init_c=init_c, unit_flag=unit_flag)
243 if l0_buf_idx == c0:258 if l0_buf_idx == c0:
244 tla.set_flag(l0a0_available)259 tla.set_flag(l0a0_available)
245 tla.set_flag(l0b0_available)260 tla.set_flag(l0b0_available)
@@ -271,6 +286,7 @@ def run(args: argparse.Namespace) -> int:
271 get_block_num,286 get_block_num,
272 create_tla_tensor,287 create_tla_tensor,
273 compare,288 compare,
289+ to_hf32,
274 )290 )
275 291 
276 torch.npu.set_device(args.device)292 torch.npu.set_device(args.device)
@@ -284,12 +300,23 @@ def run(args: argparse.Namespace) -> int:
284 dtype_a = dtypes[args.dtype_a]300 dtype_a = dtypes[args.dtype_a]
285 dtype_b = dtypes[args.dtype_b]301 dtype_b = dtypes[args.dtype_b]
286 dtype_c = dtypes[args.dtype_c]302 dtype_c = dtypes[args.dtype_c]
303+ 
287 a = torch.rand(args.m, args.k, dtype=dtype_a, device="cpu") * 10.0 - 5.0304 a = torch.rand(args.m, args.k, dtype=dtype_a, device="cpu") * 10.0 - 5.0
288 b = torch.rand(args.k, args.n, dtype=dtype_b, device="cpu") * 10.0 - 5.0305 b = torch.rand(args.k, args.n, dtype=dtype_b, device="cpu") * 10.0 - 5.0
289 c = torch.rand(args.m, args.n, dtype=dtype_c, device="cpu") * 10.0 - 5.0306 c = torch.rand(args.m, args.n, dtype=dtype_c, device="cpu") * 10.0 - 5.0
290- ref = a.float() @ b.float()307+ 
291- if dtype_c in (torch.float16, torch.bfloat16):308+ hf32_mode = tla.params.HF32Mode.HF32_NEAREST_EVEN
292- ref = ref.to(dtype_c).float()309+ enable_hf32 = (
310+ hf32_mode != tla.params.HF32Mode.HF32_DISABLE
311+ and dtype_a == torch.float32
312+ and dtype_b == torch.float32
313+ )
314+ if enable_hf32:
315+ ref = to_hf32(a, hf32_mode) @ to_hf32(b, hf32_mode)
316+ else:
317+ ref = a.float() @ b.float()
318+ if dtype_c in (torch.float16, torch.bfloat16):
319+ ref = ref.to(dtype_c).float()
293 320 
294 a = (321 a = (
295 a.contiguous() if args.layout_a == "row" else a.permute(1, 0).contiguous()322 a.contiguous() if args.layout_a == "row" else a.permute(1, 0).contiguous()
@@ -308,13 +335,18 @@ def run(args: argparse.Namespace) -> int:
308 b_tensor,335 b_tensor,
309 c_tensor,336 c_tensor,
310 TilingParams(), # default tiling: L1: (256, 256, 128); L0: (256, 256, 32)337 TilingParams(), # default tiling: L1: (256, 256, 128); L0: (256, 256, 32)
338+ hf32_mode,
311 options="--npu-arch 3510",339 options="--npu-arch 3510",
312 )340 )
313 block_num = get_block_num(args.block_num, args.device, kind="cube")341 block_num = get_block_num(args.block_num, args.device, kind="cube")
314 artifact(a_tensor, b_tensor, c_tensor, block_num=block_num)342 artifact(a_tensor, b_tensor, c_tensor, block_num=block_num)
315 torch.npu.synchronize()343 torch.npu.synchronize()
316 344 
317- passed = compare(c.detach().cpu(), ref, args.k)345+ result = c.detach().cpu()
346+ if enable_hf32:
347+ passed = compare(result, ref, enable_hf32=True)
348+ else:
349+ passed = compare(result, ref, args.k)
318 print(f"passed={passed} cache_key={artifact.cache_key}")350 print(f"passed={passed} cache_key={artifact.cache_key}")
319 print(f"kernel.o={artifact.kernel_binary_path}")351 print(f"kernel.o={artifact.kernel_binary_path}")
320 return 0 if passed else 1352 return 0 if passed else 1
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/README.mdpython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/README.md+30-17
@@ -1,24 +1,24 @@
1-# Matmul EVG 端到端示例1+# CV (Cube + Vector) 融合后处理类 端到端示例
2 2 
I
Iinit__zhb__22 天前

basic_mmad_evg更名为_epilogue后,需要更新相关测试件中命名

likedislike
3-本目录下提供的系列样例演示 **CATLASS DSL** 下 基于 Ascend950 的 GEMM + EVG(Epilogue Visitor Graph)尾处理,对齐 C++ 参考实现 `examples/64_ascend950_matmul_evg_*`3+本目录下提供的系列样例演示 **CATLASS DSL** 下系列后处理类CV(Cube + Vector)融合算子的计算过程
4 4 
5## 功能说明5## 功能说明
6 6 
7-基础矩阵乘算子实现形如 `(m, k)` 和 `(k, n)` 两矩阵法,输出形如 `(m, n)`:7+后处理类算子实现基础矩阵乘并复合后续计算步骤。
8 8 
9$$9$$
10\begin{aligned}10\begin{aligned}
11-D &= A \times B \oplus \text{Epilogue}11+D &= f(A \times B)
12\end{aligned}12\end{aligned}
13$$13$$
14 14 
15-各变体在 GEMM 之后接入不同 EVG 尾处理算子(Add、Bias、LeakyRelu、Sigmoid、Silu、Tanh 等),由 AIV 融合完成15+本目录下样例包含处理操作见后续介绍
16 16 
17 17 
18## 代码组织18## 代码组织
19 19 
20```plain20```plain
21-./basic_mmad_evg21+./basic_mmad_epilogue
22├── matmul_add.py22├── matmul_add.py
23├── matmul_add_ub.py23├── matmul_add_ub.py
24├── matmul_bias.py24├── matmul_bias.py
@@ -31,16 +31,18 @@ $$
31 31 
32| 文件 | 概述 |32| 文件 | 概述 |
33|------|------|33|------|------|
34-| [**`matmul_add.py`**](matmul_add.py) | D = A×B + X;L0C→GM + AIV。 |34+| [**`matmul_add.py`**](matmul_add.py) | 实现 `D = A@B + X` 计算功能。 |
35-| [**`matmul_add_ub.py`**](matmul_add_ub.py) | D = A×B + XL0C→UB + AIV。 |35+| [**`matmul_add_ub.py`**](matmul_add_ub.py) | 实现 `D = A@B + X` 计算功能,启用L0C -> UB通路将矩阵乘结果搬出到 UB。 |
36-| [**`matmul_bias.py`**](matmul_bias.py) | D = A×B + bias(1×N);L0C→GM + RowBroadcast。 |36+| [**`matmul_bias.py`**](matmul_bias.py) | 实现 `D = A@B + bias` 计算功能,其中 `bias` 为一维 `(n,)` 的广播向量。 |
37-| [**`matmul_leaky_relu.py`**](matmul_leaky_relu.py) | D = LeakyRelu(A×B),α=0.1;L0C→GM + AIV。 |37+| [**`matmul_leaky_relu.py`**](matmul_leaky_relu.py) | 实现 `D = LeakyRelu(A@B)` 计算功能其中`α` 默认为 `0.1`。 |
38-| [**`matmul_sigmoid.py`**](matmul_sigmoid.py) | D = Sigmoid(A×B);L0C→GM + AIV。 |38+| [**`matmul_sigmoid.py`**](matmul_sigmoid.py) | 实现 `D = Sigmoid(A@B)` 计算功能。 |
39-| [**`matmul_silu.py`**](matmul_silu.py) | D = Silu(A×B);L0C→GM + AIV。 |39+| [**`matmul_silu.py`**](matmul_silu.py) | 实现 `D = Silu(A@B)` 计算功能。 |
40-| [**`matmul_tanh.py`**](matmul_tanh.py) | D = Tanh(A×B);L0C→GM + AIV。 |40+| [**`matmul_tanh.py`**](matmul_tanh.py) | 实现 `D = Tanh(A@B)` 计算功能。 |
41 41 
42## 约束说明42## 约束说明
43 43 
44+ - 左、右矩阵及结果矩阵所支持的数据组合类型如下。
45+ 
44| 算子 | `DTYPE_A` / `DTYPE_B` | `DTYPE_C` |46| 算子 | `DTYPE_A` / `DTYPE_B` | `DTYPE_C` |
45|------|-------------------|---------|47|------|-------------------|---------|
46| add, bias, leaky_relu, sigmoid, silu | f16 / bf16 / f32 | f16 或 f32 |48| add, bias, leaky_relu, sigmoid, silu | f16 / bf16 / f32 | f16 或 f32 |
@@ -61,8 +63,10 @@ $$
61| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |63| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |
62| `--n` | `256` | 矩阵乘右矩阵 B 的列数 |64| `--n` | `256` | 矩阵乘右矩阵 B 的列数 |
63| `--k` | `256` | 矩阵乘累加轴的大小 |65| `--k` | `256` | 矩阵乘累加轴的大小 |
64-| `--layout-a` / `--layout-b` | `row` / `row` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |66+| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |
65-| `--dtype-a` / `--dtype-b` / `--dtype-c` | `f32` / `f32` / `f32` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |67+| `--dtype-a` / `--dtype-b` | `"f32"` / `"f32"` | 左、右矩阵 A、B 的数据类型,可选范围参考约束说明。 |
68+| `--dtype-c` | `"f32"` | 结果矩阵 C 的数据类型,可选范围参考约束说明(`add_ub` / `tanh` 仅支持 f32)。 |
69+| `--block-num` | `-1` | 启用的 AIC 核数,`-1` 表示自动探测可用核数(满核)。 |
66 70 
67 71 
68### 执行示例72### 执行示例
@@ -73,9 +77,18 @@ $$
73cd python/tla_dsl77cd python/tla_dsl
74 78 
75# 其余变体替换文件名即可79# 其余变体替换文件名即可
76-python examples/end_to_end/basic_mmad_evg/matmul_add.py --device 0 \80+python examples/end_to_end/basic_mmad_epilogue/matmul_add.py --device 0 \
CheaterAbec
CheaterAbecCheaterAbec22 天前

为啥要改EVG的文件夹名?

likedislike
init__zhb__
22 天前 评论:
CheaterAbec
CheaterAbec
22 天前 评论:
init__zhb__
22 天前 评论:
77 --m 256 --n 256 --k 256 \81 --m 256 --n 256 --k 256 \
78 --layout-a row --layout-b row \82 --layout-a row --layout-b row \
79 --dtype-a f16 --dtype-b f16 --dtype-c f3283 --dtype-a f16 --dtype-b f16 --dtype-c f32
80- 
81```84```
85+ 
86+默认测试条件下,预期输出:
87+ 
88+```text
89+--- mnk=(256,256,256) layout=row/row dtype=f16/f16/f32 ---
90+passed=True cache_key=<cache_key>
91+kernel.o=<cache_dir>/<cache_key>/kernel.o
92+```
93+ 
94+其中 `passed`结果为`True``False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`cache_dir` 是指定的缓存目录, `cache_key` 是编译缓存的哈希值。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_add.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_add.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_add_ub.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_add_ub.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_bias.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_bias.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_leaky_relu.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_leaky_relu.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_sigmoid.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_sigmoid.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_silu.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_silu.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_tanh.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_tanh.py+0-0
文件重命名但无更改。
@@ -1,6 +1,6 @@
1# StreamK MMAD 端到端示例1# StreamK MMAD 端到端示例
2 2 
3-本目录下的样例演示 **CATLASS DSL** 下 StreamK MatMul 的实现,对齐 C++ 参考实现`examples/66_ascend950_streamk_matmul`3+本目录下的样例演示 **CATLASS DSL** 下 StreamK MatMul 的实现。
4 4 
5## 功能说明5## 功能说明
6 6 
@@ -53,15 +53,13 @@ StreamK 通过将 K 维度的计算分摊到多个核上以均衡负载:normal
53| 参数 | 默认值 | 说明 |53| 参数 | 默认值 | 说明 |
54|------|--------|------|54|------|--------|------|
55| `--device` | `0` | 上板执行使用的 NPU 设备号。 |55| `--device` | `0` | 上板执行使用的 NPU 设备号。 |
56-| `--run` | 默认开启 | 上板并校验精度。 |
57| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |56| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |
58| `--n` | `256` | 矩阵乘右矩阵 B 的列数 |57| `--n` | `256` | 矩阵乘右矩阵 B 的列数 |
59| `--k` | `512` | 矩阵乘累加轴的大小 |58| `--k` | `512` | 矩阵乘累加轴的大小 |
60| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"``"col"`,表示行优先或列优先布局。 |59| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"``"col"`,表示行优先或列优先布局。 |
61| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |60| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |
62-| `--block` | `None` | 启用的 AIC 核数。 |61+| `--block-num` | `-1` | 启用的 AIC 核数,`-1` 表示自动探测可用核数(满核)。 |
63- 62+| `--atol` | `1e-3` | 精度比对时的绝对容差。 |
64-其余参数(`--sentinel``--atol``--cache-dir``--force-recompile``--no-cache` 等)详见 `--help`
65 63 
66### 执行示例64### 执行示例
67 65 
@@ -70,18 +68,18 @@ StreamK 通过将 K 维度的计算分摊到多个核上以均衡负载:normal
70```bash68```bash
71cd python/tla_dsl69cd python/tla_dsl
72 70 
73-# 上板并校验(默认即 --run,精度校验默认开启)71+# 上板并校验精度
74-python examples/end_to_end/basic_mmad_streamk/basic_mmad_streamk.py --run --device 0 \72+python examples/end_to_end/basic_mmad_streamk/basic_mmad_streamk.py --device 0 \
75 --layout-a row --layout-b col \73 --layout-a row --layout-b col \
76 --dtype-a f16 --dtype-b f16 --dtype-c f3274 --dtype-a f16 --dtype-b f16 --dtype-c f32
77```75```
78 76 
77+默认测试条件下,预期输出:
79 78 
80- 79+```text
81-```bash80+--- mnk=(256,256,512) layout=row/col dtype=f16/f16/f32 ---
82-python examples/end_to_end/basic_mmad_streamk/basic_mmad_streamk.py --help81+passed=True cache_key=<cache_key>
82+kernel.o=<cache_dir>/<cache_key>/kernel.o
83```83```
84 84 
85-执行测试后预期输出:85+其中 `passed`结果为`True`或`False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`cache_dir` 是指定的缓存目录 `cache_key` 是编译缓存的哈希值。
86- 
87-默认运行会打印 `compile_ok=True``host=torch_npu``launch_ok=True``kernel.o` 路径,以及 `C unchanged?` / `C equals expected matmul?` / `first mismatch=...` 等(与 `m×n×k`、block、`--sentinel`、dtype 有关;golden 为 **Torch** 在 NPU 上的 matmul)。
@@ -60,7 +60,7 @@ basic_vadd.py [-h] [--device DEVICE] [--n N]
60|------|--------|------|60|------|--------|------|
61| `--device` | `0` | 上板执行使用的 NPU 设备号。 |61| `--device` | `0` | 上板执行使用的 NPU 设备号。 |
62| `--n` | `400` | 向量长度。 |62| `--n` | `400` | 向量长度。 |
63-| `--block-num` | `-1`(依据所使用的 NPU 设备采集其满核值) | 启用的 AI Vector 核数 |63+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
64| `--dtype` | `"f32"` | 数据类型,可选 `"f32"``"f16"``"i8"``"i16"``"i32"`。 |64| `--dtype` | `"f32"` | 数据类型,可选 `"f32"``"f16"``"i8"``"i16"``"i32"`。 |
65| `--use-mutex` | `False` | 切换到显式 Mutex `lock` / `unlock` 同步(执行 `basic_vadd_mutex`)。 |65| `--use-mutex` | `False` | 切换到显式 Mutex `lock` / `unlock` 同步(执行 `basic_vadd_mutex`)。 |
66| `--use-mutex-with` | `False` | 切换到 `with tla.mutex_guard(...)` 同步(执行 `basic_vadd_mutex_with`)。 |66| `--use-mutex-with` | `False` | 切换到 `with tla.mutex_guard(...)` 同步(执行 `basic_vadd_mutex_with`)。 |
@@ -125,7 +125,7 @@ tla.copy(ub_a, gm_a)
125mutex_ub_a.unlock(pipe=tla.arch.MTE2)125mutex_ub_a.unlock(pipe=tla.arch.MTE2)
126```126```
127 127 
128-## basic_vadd_mutex_with128+### basic_vadd_mutex_with
129 129 
130**文件**:[`basic_vadd.py`](basic_vadd.py#L127)130**文件**:[`basic_vadd.py`](basic_vadd.py#L127)
131 131 
@@ -139,7 +139,7 @@ with tla.mutex_guard(mutex_ub_a):
139 tla.copy(ub_a, gm_a)139 tla.copy(ub_a, gm_a)
140```140```
141 141 
142-## basic_vadd_atomic_add142+### basic_vadd_atomic_add
143 143 
144**文件**:[`basic_vadd.py`](basic_vadd.py#L175)144**文件**:[`basic_vadd.py`](basic_vadd.py#L175)
145 145 
@@ -1,6 +1,6 @@
1# Batched Matmul 端到端示例1# Batched Matmul 端到端示例
2 2 
3-本目录下的样例演示 **CATLASS DSL** 下的批量矩阵乘,对齐 C++ 参考实现 `examples/67_ascend950_batched_matmul*`3+本目录下的样例演示 **CATLASS DSL** 下的批量矩阵乘。
4 4 
5## 功能说明5## 功能说明
6 6 
@@ -12,8 +12,6 @@ $$
12 12 
13各 batch 的 `(M, N, K)` 相同。13各 batch 的 `(M, N, K)` 相同。
14 14 
15- 
16- 
17## 代码组织15## 代码组织
18 16 
19```plain17```plain
@@ -22,21 +20,21 @@ $$
22└── README.md20└── README.md
23```21```
24 22 
25-| 文件 | 概述 |23+| 文件 | 概述 |
26-|------|------|24+| --------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
27-| [**`batched_matmul.py`**](batched_matmul.py) | 设备侧 `@tla.kernel` 与 host 侧运行/校验逻辑同文件。执行数据生成、compile/launch、以及golden比对。 |25+| [**`batched_matmul.py`**](batched_matmul.py) | 设备侧`@tla.kernel` 与 host 侧运行/校验逻辑同文件。执行数据生成、compile/launch、以及golden比对。 |
28 26 
29## 约束说明27## 约束说明
30 28 
31- - 左、右矩阵及结果矩阵所支持的数据组合类型如下。29+- 左、右矩阵及结果矩阵所支持的数据组合类型如下。
32 30 
33| `DTYPE_A` | `DTYPE_B` | `DTYPE_C` |31| `DTYPE_A` | `DTYPE_B` | `DTYPE_C` |
34-|---------|---------|------------------|32+| ----------- | ----------- | ----------- |
35-| f16 | f16 | f32 |33+| f16 | f16 | f32 |
36-| f16 | f16 | f16 |34+| f16 | f16 | f16 |
37-| bf16 | bf16 | f32 |35+| bf16 | bf16 | f32 |
38-| bf16 | bf16 | bf16 |36+| bf16 | bf16 | bf16 |
39-| f32 | f32 | f32 |37+| f32 | f32 | f32 |
40 38 
41## 使用示例39## 使用示例
42 40 
@@ -44,33 +42,34 @@ $$
44 42 
45### 命令行参数43### 命令行参数
46 44 
47-| 参数 | 默认值 | 说明 |45+| 参数 | 默认值 | 说明 |
48-|------|--------|------|46+| --------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------ |
49-| `--device` | `0` | 上板执行使用的 NPU 设备号。 |47+| `--device` | `0` | 上板执行使用的 NPU 设备号。 |
50-| `--batch` | `5` | batch 数 B。 |48+| `--batch` | `5` | batch 数 B。 |
51-| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |49+| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |
52-| `--n` | `512` | 矩阵乘右矩阵 B 的列数 |50+| `--n` | `512` | 矩阵乘右矩阵 B 的列数 |
53-| `--k` | `1024` | 矩阵乘累加轴的大小 |51+| `--k` | `1024` | 矩阵乘累加轴的大小 |
54-| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |52+| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"` 或 `"col"`,表示行优先或列优先布局。 |
55-| `--dtype-a` / `--dtype-b` / `--dtype-c` | `f16` / `f16` / `f16` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |53+| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |
56-| `--block` | `8` | 启用的核数 |54+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
57 55 
58### 执行示例56### 执行示例
59 57 
60`python/tla_dsl` 目录下执行:58`python/tla_dsl` 目录下执行:
61 59 
62```bash60```bash
63-cd "${CATLASS_ROOT}/python/tla_dsl/examples/end_to_end/batched_matmul"61+cd python/tla_dsl
64- 
65-python batched_matmul.py --run --device 0 --batch 4 --m 256 --n 256 --k 256 --block 8
66 62 
63+python examples/end_to_end/batched_matmul/batched_matmul.py --device 0 \
64+ --batch 4 --m 256 --n 256 --k 256
67```65```
68 66 
69-执行测试,预期输出:67+默认测试条件下,预期输出:
70 68 
71```text69```text
72-compile_ok=True ...70+--- batch=(4) mnk=(256,256,256) layout=row/row dtype=f16/f16/f32 ---
73-launch_ok=True71+passed=True cache_key=<cache_key>
74-C equals batched golden? True72+kernel.o=<cache_dir>/<cache_key>/kernel.o
75-first mismatch=None
76```73```
74+ 
75+其中 `passed`结果为`True``False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`cache_dir` 是指定的缓存目录, `cache_key` 是编译缓存的哈希值。
@@ -10,7 +10,7 @@
10 10 
11from .golden import compare, tolerance11from .golden import compare, tolerance
12from .params import TilingParams, SwizzleParams12from .params import TilingParams, SwizzleParams
13-from .utils import create_tla_tensor, get_block_num13+from .utils import create_tla_tensor, get_block_num, to_hf32
14 14 
15__all__ = [15__all__ = [
16 # struct-like params16 # struct-like params
@@ -19,6 +19,7 @@ __all__ = [
19 # helper function19 # helper function
20 "create_tla_tensor",20 "create_tla_tensor",
21 "get_block_num",21 "get_block_num",
22+ "to_hf32",
22 # golden compare23 # golden compare
23 "compare",24 "compare",
24 "tolerance",25 "tolerance",
@@ -12,6 +12,12 @@ from typing import overload
12 12 
13import torch13import torch
14 14 
15+# HF32 mixed tolerance thresholds.
16+_HF32_RTOL = 2.0**-9
17+_HF32_ATOL = 2.0**-10
18+_HF32_REQUIRED_MATCHED_RATIO = 0.99
19+_HF32_MAX_ABS_ERROR_LIMIT = 1e-1
20+ 
15 21 
16def tolerance(22def tolerance(
17 expected: torch.Tensor,23 expected: torch.Tensor,
@@ -32,6 +38,27 @@ def tolerance(
32 return rtol * torch.maximum(torch.full_like(expected, floor), expected.abs())38 return rtol * torch.maximum(torch.full_like(expected, floor), expected.abs())
33 39 
34 40 
41+def _compare_hf32(
42+ result: torch.Tensor,
43+ expected: torch.Tensor,
44+) -> bool:
45+ """Compare result against an HF32-semantic golden."""
46+ result = result.float()
47+ expected = expected.float()
48+ diff = (result - expected).abs()
49+ matched = diff <= _HF32_ATOL + _HF32_RTOL * expected.abs()
50+ matched_ratio = matched.float().mean().item()
51+ max_abs_error = diff.max().item()
52+ ulp = torch.finfo(expected.dtype).eps * (
53+ 2.0 ** torch.floor(torch.log2(expected.abs().max()))
54+ )
55+ max_abs_error_limit = max(_HF32_MAX_ABS_ERROR_LIMIT, 32.0 * ulp.item())
56+ return bool(
57+ matched_ratio >= _HF32_REQUIRED_MATCHED_RATIO
58+ and max_abs_error <= max_abs_error_limit
59+ )
60+ 
61+ 
35@overload62@overload
36def compare(63def compare(
37 result: torch.Tensor,64 result: torch.Tensor,
@@ -48,6 +75,7 @@ def compare(
48 result: torch.Tensor,75 result: torch.Tensor,
49 expected: torch.Tensor,76 expected: torch.Tensor,
50 *,77 *,
78+ enable_hf32: bool = False,
51 rtol: float = 0.0,79 rtol: float = 0.0,
52 atol: float = 0.0,80 atol: float = 0.0,
53) -> bool: ...81) -> bool: ...
@@ -61,15 +89,21 @@ def compare(
61 rtol: float | None = None,89 rtol: float | None = None,
62 floor: float | None = None,90 floor: float | None = None,
63 atol: float = 0.0,91 atol: float = 0.0,
92+ enable_hf32: bool = False,
64) -> bool:93) -> bool:
65 """Compare ``result`` against ``expected`` with given threshold.94 """Compare ``result`` against ``expected`` with given threshold.
66 95 
67- Two call forms are supported:96+ Three call forms are supported:
68 97 
69 1. Accumulative precision standard (``k`` given), for matmul-like operators.98 1. Accumulative precision standard (``k`` given), for matmul-like operators.
70 2. Generic element-wise check.99 2. Generic element-wise check.
100+ 3. HF32 mixed tolerance (``enable_hf32=True``).
71 """101 """
102+ if enable_hf32:
103+ # Use mixed tolerance for HF32.
104+ return _compare_hf32(result, expected)
72 if k is not None and isinstance(k, int):105 if k is not None and isinstance(k, int):
106+ # Single precision standard.
73 is_bf16 = result.dtype == torch.bfloat16107 is_bf16 = result.dtype == torch.bfloat16
74 result, expected = result.float(), expected.float()108 result, expected = result.float(), expected.float()
75 return bool(109 return bool(
@@ -81,6 +115,7 @@ def compare(
81 if result.dtype != expected.dtype:115 if result.dtype != expected.dtype:
82 raise TypeError("the data type between the golden and the result do not match")116 raise TypeError("the data type between the golden and the result do not match")
83 if result.dtype in (torch.float32, torch.float16, torch.bfloat16):117 if result.dtype in (torch.float32, torch.float16, torch.bfloat16):
118+ # Generic element-wise precision check.
84 return bool(119 return bool(
85 torch.isclose(120 torch.isclose(
86 result, expected, rtol=0.0 if rtol is None else rtol, atol=atol121 result, expected, rtol=0.0 if rtol is None else rtol, atol=atol
@@ -38,3 +38,35 @@ def get_block_num(block_num: int, device: int = 0, *, kind: str = "vector") -> i
38def create_tla_tensor(buf, layout: str):38def create_tla_tensor(buf, layout: str):
39 tag = tla.arch.RowMajor if layout == "row" else tla.arch.ColumnMajor39 tag = tla.arch.RowMajor if layout == "row" else tla.arch.ColumnMajor
40 return from_dlpack(buf.contiguous(), layout_tag=tag).mark_layout_dynamic()40 return from_dlpack(buf.contiguous(), layout_tag=tag).mark_layout_dynamic()
41+ 
42+ 
43+def to_hf32(
44+ x: torch.Tensor,
45+ hf32_mode: tla.params.HF32Mode,
46+) -> torch.Tensor:
47+ """Simulate HF32 rounding mode on f32 values.
48+ 
49+ HF32 keeps the FP32 sign and 8-bit exponent, and reduces the mantissa to
50+ 11 significant bits (10 explicit mantissa bits, close to FP16):
51+ 
52+ - ``HF32_NEAREST_ZERO`` rounds to nearest, ties toward zero.
53+ - ``HF32_NEAREST_EVEN`` rounds them to nearest-even.
54+ """
55+ if not isinstance(hf32_mode, tla.params.HF32Mode):
56+ raise TypeError(
57+ f"hf32_mode must be a tla.params.HF32Mode, got {type(hf32_mode).__name__}"
58+ )
59+ x = x.float()
60+ if hf32_mode == tla.params.HF32Mode.HF32_DISABLE:
61+ return x
62+ 
63+ bits = x.contiguous().view(torch.int32)
64+ if hf32_mode == tla.params.HF32Mode.HF32_NEAREST_ZERO:
65+ rounded_bits = (bits + 0x0FFF) & ~0x1FFF
66+ elif hf32_mode == tla.params.HF32Mode.HF32_NEAREST_EVEN:
67+ lsb = (bits >> 13) & 1
68+ rounded_bits = (bits + 0x0FFF + lsb) & ~0x1FFF
69+ else:
70+ raise ValueError(f"Unsupported HF32 mode: {hf32_mode!r}")
71+ 
72+ return rounded_bits.view(torch.float32)
@@ -95,7 +95,7 @@ flash_attention_infer.py [-h] [--device DEVICE] [--dtype {f16,bf16}]
95| `--kvheadnum` | `1` | KV 头数,覆盖 `KV_HEAD_NUM`。 |95| `--kvheadnum` | `1` | KV 头数,覆盖 `KV_HEAD_NUM`。 |
96| `--qseqlen` | `117` | Q 序列长度,覆盖 `Q_SEQ`。 |96| `--qseqlen` | `117` | Q 序列长度,覆盖 `Q_SEQ`。 |
97| `--kvseqlen` | `512` | KV 序列长度,覆盖 `KV_SEQ`。 |97| `--kvseqlen` | `512` | KV 序列长度,覆盖 `KV_SEQ`。 |
98-| `--block-num` | `-1` | 启用的 AI Core 核数`-1` 表示满 AIC`cube_core_num`)。 |98+| `--block-num` | `-1` | 启用的核数`-1` 表示自动探测可用核数满核)。 |
99| `--sentinel` | `-7.0` | O 的初始值,用于对比检测 kernel 是否真正写入。 |99| `--sentinel` | `-7.0` | O 的初始值,用于对比检测 kernel 是否真正写入。 |
100 100 
101### 执行示例101### 执行示例
@@ -1,6 +1,6 @@
1# Grouped Matmul Slice-M 端到端示例1# Grouped Matmul Slice-M 端到端示例
2 2 
3-本目录下的样例演示 **CATLASS DSL** 下按 M 切分的分组矩阵乘,对齐 C++ 参考实现`examples/60_ascend950_grouped_matmul_slice_m`3+本目录下的样例演示 **CATLASS DSL** 下按 M 切分的分组矩阵乘。
4 4 
5## 功能说明5## 功能说明
6 6 
@@ -49,22 +49,29 @@ $$
49| `--k` | `256` | 矩阵乘累加轴的大小 |49| `--k` | `256` | 矩阵乘累加轴的大小 |
50| `--groups` | `4` | 分组数 G。 |50| `--groups` | `4` | 分组数 G。 |
51| `--group-mode` | `random` | 组切分模式,可选 `average``random`。 |51| `--group-mode` | `random` | 组切分模式,可选 `average``random`。 |
52-| `--layout-a` / `--layout-b` | `row` / `row` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |52+| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |
53-| `--dtype-a` / `--dtype-b` / `--dtype-c` | `f16` / `f16` / `f16` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |53+| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f16"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |
54-| `--block` | `8` | 启用的核数。 |54+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
55 55 
56### 执行示例56### 执行示例
57 57 
58`python/tla_dsl` 目录下执行:58`python/tla_dsl` 目录下执行:
59 59 
60```bash60```bash
61-cd "${CATLASS_ROOT}/python/tla_dsl"61+cd python/tla_dsl
62- 
63-python examples/end_to_end/grouped_matmul_slice_m/grouped_matmul_slice_m.py \
64- --run --device 4 --m 1024 --n 256 --k 256 --groups 4 --group-mode average --block 8
65 62 
63+python examples/end_to_end/grouped_matmul_slice_m/grouped_matmul_slice_m.py --device 0 \
64+ --m 1024 --n 256 --k 256 --groups 4 --group-mode average
66```65```
67 66 
68-执行测试,预期输出:67+默认测试条件下,预期输出:
69 68 
70-成功时可见 `compile_ok` / `launch_ok` 与 golden 比对结果。69+```text
70+--- groups=(4) mnk=(1024,256,256) layout=row/row dtype=f16/f16/f16 group_mode=average ---
71+GROUP_CURRENT_M=(256, 256, 256, 256)
72+GROUP_LIST_PREFIX=(0, 256, 512, 768, 1024)
73+passed=True cache_key=<cache_key>
74+kernel.o=<cache_dir>/<cache_key>/kernel.o
75+```
76+ 
77+其中 `passed`结果为`True``False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`cache_dir` 是指定的缓存目录, `cache_key` 是编译缓存的哈希值。
@@ -1,6 +1,6 @@
1# 多核切 K Matmul 端到端示例1# 多核切 K Matmul 端到端示例
2 2 
3-本目录下提供的样例演示 **CATLASS DSL** 下多核切 K 矩阵乘的两种实现,对齐 C++ 参考实现 `examples/68_ascend950_multi_core_splitk_matmul` 和 `examples/69_ascend950_tail_multi_core_splitk_matmul` 3+本目录下提供的样例演示 **CATLASS DSL** 下多核切 K 矩阵乘的两种实现。
4 4 
5## 功能说明5## 功能说明
6 6 
@@ -12,7 +12,7 @@ C_{i,j} &= \Sigma_{k} A_{i,k}B_{k,j}
12\end{aligned}12\end{aligned}
13$$13$$
14 14 
15-Split-K 将 K 维度的计算切分到多个核上并行执行,各核的部分积累入 workspace,再由 AIV 做 ReduceAdd 归约得到最终结果 C15+Split-K 将 K 维度的计算切分到多个核上并行执行,各核的计算结果写回 GM,再由 AIV 做 ReduceAdd 归约计算
16 16 
17## 代码组织17## 代码组织
18 18 
@@ -25,8 +25,8 @@ Split-K 将 K 维度的计算切分到多个核上并行执行,各核的部分
25 25 
26| 文件 | 概述 |26| 文件 | 概述 |
27|------|------|27|------|------|
28-| [**`multi_core_splitk_matmul.py`**](multi_core_splitk_matmul.py) | 设备侧 `@tla.kernel` 与 host 侧运行/校验逻辑同文件。全部 M×N tile K 维 split-K 写入 workspace,AIV ReduceAdd 写回 GM C。 |28+| [**`multi_core_splitk_matmul.py`**](multi_core_splitk_matmul.py) | 全部 Tile 块在累加轴 K方向上做切分并在 AIV 核进行规约(ReduceAdd写回 GM。 |
29-| [**`tail_multi_core_splitk_matmul.py`**](tail_multi_core_splitk_matmul.py) | 设备侧 `@tla.kernel` 与 host 侧运行/校验逻辑同文件。normal tile full-K 直接写回 gmC;tail tile 再做 split-K + ReduceAdd。 |29+| [**`tail_multi_core_splitk_matmul.py`**](tail_multi_core_splitk_matmul.py) | 针对尾轮采取上述多核切K优化,以达成负载均衡。 |
30 30 
31## 约束说明31## 约束说明
32 32 
@@ -45,7 +45,7 @@ Split-K 将 K 维度的计算切分到多个核上并行执行,各核的部分
45 45 
46### 命令行参数46### 命令行参数
47 47 
48-CLI 与 basic 同形,主要参数如下:48+接收命令行参数如下:
49 49 
50| 参数 | 默认值 | 说明 |50| 参数 | 默认值 | 说明 |
51|------|--------|------|51|------|--------|------|
@@ -53,21 +53,32 @@ CLI 与 basic 同形,主要参数如下:
53| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |53| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |
54| `--n` | `512` | 矩阵乘右矩阵 B 的列数 |54| `--n` | `512` | 矩阵乘右矩阵 B 的列数 |
55| `--k` | `1024` | 矩阵乘累加轴的大小 |55| `--k` | `1024` | 矩阵乘累加轴的大小 |
56-| `--layout-a` / `--layout-b` | `row` / `row` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |56+| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |
57| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f16"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |57| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f16"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |
58+| `--block-num` | `-1` | 启用的 AIC 核数,`-1` 表示自动探测可用核数(满核)。 |
58 59 
59### 执行示例60### 执行示例
60 61 
61`python/tla_dsl` 目录下执行:62`python/tla_dsl` 目录下执行:
62 63 
63```bash64```bash
64-export PYTHONPATH="$(pwd):${PYTHONPATH:-}"65+cd python/tla_dsl
65 66 
66-# multi_core_splitk67+# multi_core_splitk (指定 NPU 设备ID, m/n/k 的值)
67python examples/end_to_end/multi_core_splitk_matmul/multi_core_splitk_matmul.py \68python examples/end_to_end/multi_core_splitk_matmul/multi_core_splitk_matmul.py \
68 --device 0 --m 256 --n 512 --k 102469 --device 0 --m 256 --n 512 --k 1024
69 70 
70-# tail_multi_core_splitk71+# tail_multi_core_splitk (指定 NPU 设备ID, m/n/k 的值)
71python examples/end_to_end/multi_core_splitk_matmul/tail_multi_core_splitk_matmul.py \72python examples/end_to_end/multi_core_splitk_matmul/tail_multi_core_splitk_matmul.py \
72 --device 0 --m 2048 --n 1024 --k 204873 --device 0 --m 2048 --n 1024 --k 2048
73```74```
75+ 
76+默认测试条件下,预期输出:
77+ 
78+```text
79+--- mnk=(256,512,1024) layout=row/row dtype=f16/f16/f16 ---
80+passed=True mismatch=0.0000% (budget=0.1000%) cache_key=<cache_key>
81+kernel.o=<cache_dir>/<cache_key>/kernel.o
82+```
83+ 
84+其中 `passed`结果为`True``False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`mismatch`为超容差元素占比,不高于 `budget` 即判定通过;`cache_dir` 是指定的缓存目录, `cache_key` 是编译缓存的哈希值。
@@ -8,7 +8,7 @@
8向量运算是 NPU 上基础的计算原语,在 AIV 物理核上执行,整体执行流程包括:8向量运算是 NPU 上基础的计算原语,在 AIV 物理核上执行,整体执行流程包括:
91. 构造 GM (Global memory)上的输入/输出 `tla.Tensor`91. 构造 GM (Global memory)上的输入/输出 `tla.Tensor`
102. 启动MTE2,将数据搬运至 UB (Unified Buffer);102. 启动MTE2,将数据搬运至 UB (Unified Buffer);
11-3. 加载至寄存器上,以 `VL`(向量寄存器位宽)为粒度分块执行各类向量指令;11+3. 加载至寄存器上,以 `VL`(向量寄存器位宽, 256 字节)为粒度分块执行各类向量指令;
124. 输出回 UB,然后启动 MTE3,将数据搬运回 GM。124. 输出回 UB,然后启动 MTE3,将数据搬运回 GM。
13 13 
14 14 
@@ -191,7 +191,7 @@ def _cases(device: int) -> Iterator[tuple[str, list[list[str]]]]:
191 "--groups", "3", "--m", "768", "--n", "333", "--k", "333", *dev]]191 "--groups", "3", "--m", "768", "--n", "333", "--k", "333", *dev]]
192 ) 192 )
193 193 
194- # --- basic_mmad_evg: multiple epilogue examples ---194+ # --- basic_mmad_epilogue: multiple epilogue examples ---
195 for op in EVG_OPS:195 for op in EVG_OPS:
196 if op in ("add_ub", "tanh"):196 if op in ("add_ub", "tanh"):
197 # f32 (dtype-c) only examples197 # f32 (dtype-c) only examples
@@ -209,9 +209,9 @@ def _cases(device: int) -> Iterator[tuple[str, list[list[str]]]]:
209 for m, n, k in MMAD_SHAPES:209 for m, n, k in MMAD_SHAPES:
210 for dab, dc in triples:210 for dab, dc in triples:
211 yield (211 yield (
212- f"mmad-evg-{op.replace('_', '-')}-{m}x{n}x{k}-{dab}-{dc}",212+ f"mmad-epilogue-{op.replace('_', '-')}-{m}x{n}x{k}-{dab}-{dc}",
213 [[213 [[
214- f"basic_mmad_evg/matmul_{op}.py",214+ f"basic_mmad_epilogue/matmul_{op}.py",
215 "--m", m, "--n", n, "--k", k,215 "--m", m, "--n", n, "--k", k,
216 "--dtype-a", dab, "--dtype-b", dab, "--dtype-c", dc,216 "--dtype-a", dab, "--dtype-b", dab, "--dtype-c", dc,
217 *dev217 *dev
@@ -19,7 +19,7 @@
19# interleave_op.py, load_dintlv_op.py, load_store_mask.py, squeeze_op.py,19# interleave_op.py, load_dintlv_op.py, load_store_mask.py, squeeze_op.py,
20# register_control_flow.py, load_and_store_scalar_after_reduction.py, load_us_b8_op.py,20# register_control_flow.py, load_and_store_scalar_after_reduction.py, load_us_b8_op.py,
21# cast_multi.py, gather_op.py).21# cast_multi.py, gather_op.py).
22-# python/tla_dsl/examples/end_to_end/basic_mmad_evg (matmul_add.py, matmul_add_ub.py,22+# python/tla_dsl/examples/end_to_end/basic_mmad_epilogue (matmul_add.py, matmul_add_ub.py,
23# matmul_bias.py, matmul_leaky_relu.py, matmul_sigmoid.py, matmul_silu.py, matmul_tanh.py).23# matmul_bias.py, matmul_leaky_relu.py, matmul_sigmoid.py, matmul_silu.py, matmul_tanh.py).
24# python/tla_dsl/examples/end_to_end/flash_attention_infer (flash_attention_infer.py).24# python/tla_dsl/examples/end_to_end/flash_attention_infer (flash_attention_infer.py).
25# python/tla_dsl/examples/end_to_end/multi_core_splitk_matmul (multi_core_splitk_matmul.py,25# python/tla_dsl/examples/end_to_end/multi_core_splitk_matmul (multi_core_splitk_matmul.py,
@@ -118,13 +118,13 @@ BATCHED_MATMUL_REL="examples/end_to_end/batched_matmul/batched_matmul.py"
118FLASH_ATTENTION_INFER_REL="examples/end_to_end/flash_attention_infer/flash_attention_infer.py"118FLASH_ATTENTION_INFER_REL="examples/end_to_end/flash_attention_infer/flash_attention_infer.py"
119MULTI_CORE_SPLITK_REL="examples/end_to_end/multi_core_splitk_matmul/multi_core_splitk_matmul.py"119MULTI_CORE_SPLITK_REL="examples/end_to_end/multi_core_splitk_matmul/multi_core_splitk_matmul.py"
120TAIL_MULTI_CORE_SPLITK_REL="examples/end_to_end/multi_core_splitk_matmul/tail_multi_core_splitk_matmul.py"120TAIL_MULTI_CORE_SPLITK_REL="examples/end_to_end/multi_core_splitk_matmul/tail_multi_core_splitk_matmul.py"
121-BASIC_MMAD_EVG_ADD_REL="examples/end_to_end/basic_mmad_evg/matmul_add.py"121+BASIC_MMAD_EPILOGUE_ADD_REL="examples/end_to_end/basic_mmad_epilogue/matmul_add.py"
122-BASIC_MMAD_EVG_ADD_UB_REL="examples/end_to_end/basic_mmad_evg/matmul_add_ub.py"122+BASIC_MMAD_EPILOGUE_ADD_UB_REL="examples/end_to_end/basic_mmad_epilogue/matmul_add_ub.py"
123-BASIC_MMAD_EVG_BIAS_REL="examples/end_to_end/basic_mmad_evg/matmul_bias.py"123+BASIC_MMAD_EPILOGUE_BIAS_REL="examples/end_to_end/basic_mmad_epilogue/matmul_bias.py"
124-BASIC_MMAD_EVG_LEAKY_RELU_REL="examples/end_to_end/basic_mmad_evg/matmul_leaky_relu.py"124+BASIC_MMAD_EPILOGUE_LEAKY_RELU_REL="examples/end_to_end/basic_mmad_epilogue/matmul_leaky_relu.py"
125-BASIC_MMAD_EVG_SIGMOID_REL="examples/end_to_end/basic_mmad_evg/matmul_sigmoid.py"125+BASIC_MMAD_EPILOGUE_SIGMOID_REL="examples/end_to_end/basic_mmad_epilogue/matmul_sigmoid.py"
126-BASIC_MMAD_EVG_SILU_REL="examples/end_to_end/basic_mmad_evg/matmul_silu.py"126+BASIC_MMAD_EPILOGUE_SILU_REL="examples/end_to_end/basic_mmad_epilogue/matmul_silu.py"
127-BASIC_MMAD_EVG_TANH_REL="examples/end_to_end/basic_mmad_evg/matmul_tanh.py"127+BASIC_MMAD_EPILOGUE_TANH_REL="examples/end_to_end/basic_mmad_epilogue/matmul_tanh.py"
128CAST_MULTI_REL="examples/end_to_end/vector_ops/cast_multi.py"128CAST_MULTI_REL="examples/end_to_end/vector_ops/cast_multi.py"
129GATHER_OP_REL="examples/end_to_end/vector_ops/gather_op.py"129GATHER_OP_REL="examples/end_to_end/vector_ops/gather_op.py"
130 130 
@@ -166,7 +166,7 @@ Run end-to-end validation for:
166 - squeeze_op (squeeze_op.py squeeze --all-dtypes)166 - squeeze_op (squeeze_op.py squeeze --all-dtypes)
167 - register_control_flow (register_control_flow.py register_carriers:167 - register_control_flow (register_control_flow.py register_carriers:
168 mixed VectorSSA/MaskSSA scf.for carriers and masked store)168 mixed VectorSSA/MaskSSA scf.for carriers and masked store)
169- - basic_mmad_evg (matmul_add.py, ...: CV fused examples)169+ - basic_mmad_epilogue (matmul_add.py, ...: CV fused examples)
170 - flash_attention_infer (flash_attention_infer.py)170 - flash_attention_infer (flash_attention_infer.py)
171 - multi_core_splitk_matmul (multi_core_splitk_matmul.py: using split-k strategy for workload balancing)171 - multi_core_splitk_matmul (multi_core_splitk_matmul.py: using split-k strategy for workload balancing)
172 - basic_mmad_streamk (basic_mmad_streamk.py: streamK workload balancing)172 - basic_mmad_streamk (basic_mmad_streamk.py: streamK workload balancing)
@@ -459,32 +459,32 @@ if [[ ! -f "${CATLASS_DSL_DIR}/${GROUPED_MATMUL_SLICEM_REL}" ]]; then
459 echo "error: missing ${GROUPED_MATMUL_SLICEM_REL} under ${CATLASS_DSL_DIR}" >&2459 echo "error: missing ${GROUPED_MATMUL_SLICEM_REL} under ${CATLASS_DSL_DIR}" >&2
460 exit 1460 exit 1
461fi461fi
462-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_ADD_REL}" ]]; then462+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_ADD_REL}" ]]; then
463- echo "error: missing ${BASIC_MMAD_EVG_ADD_REL} under ${CATLASS_DSL_DIR}" >&2463+ echo "error: missing ${BASIC_MMAD_EPILOGUE_ADD_REL} under ${CATLASS_DSL_DIR}" >&2
464 exit 1464 exit 1
465fi465fi
466-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_ADD_UB_REL}" ]]; then466+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_ADD_UB_REL}" ]]; then
467- echo "error: missing ${BASIC_MMAD_EVG_ADD_UB_REL} under ${CATLASS_DSL_DIR}" >&2467+ echo "error: missing ${BASIC_MMAD_EPILOGUE_ADD_UB_REL} under ${CATLASS_DSL_DIR}" >&2
468 exit 1468 exit 1
469fi469fi
470-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_BIAS_REL}" ]]; then470+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_BIAS_REL}" ]]; then
471- echo "error: missing ${BASIC_MMAD_EVG_BIAS_REL} under ${CATLASS_DSL_DIR}" >&2471+ echo "error: missing ${BASIC_MMAD_EPILOGUE_BIAS_REL} under ${CATLASS_DSL_DIR}" >&2
472 exit 1472 exit 1
473fi473fi
474-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_LEAKY_RELU_REL}" ]]; then474+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_LEAKY_RELU_REL}" ]]; then
475- echo "error: missing ${BASIC_MMAD_EVG_LEAKY_RELU_REL} under ${CATLASS_DSL_DIR}" >&2475+ echo "error: missing ${BASIC_MMAD_EPILOGUE_LEAKY_RELU_REL} under ${CATLASS_DSL_DIR}" >&2
476 exit 1476 exit 1
477fi477fi
478-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_SIGMOID_REL}" ]]; then478+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_SIGMOID_REL}" ]]; then
479- echo "error: missing ${BASIC_MMAD_EVG_SIGMOID_REL} under ${CATLASS_DSL_DIR}" >&2479+ echo "error: missing ${BASIC_MMAD_EPILOGUE_SIGMOID_REL} under ${CATLASS_DSL_DIR}" >&2
480 exit 1480 exit 1
481fi481fi
482-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_SILU_REL}" ]]; then482+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_SILU_REL}" ]]; then
483- echo "error: missing ${BASIC_MMAD_EVG_SILU_REL} under ${CATLASS_DSL_DIR}" >&2483+ echo "error: missing ${BASIC_MMAD_EPILOGUE_SILU_REL} under ${CATLASS_DSL_DIR}" >&2
484 exit 1484 exit 1
485fi485fi
486-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_TANH_REL}" ]]; then486+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_TANH_REL}" ]]; then
487- echo "error: missing ${BASIC_MMAD_EVG_TANH_REL} under ${CATLASS_DSL_DIR}" >&2487+ echo "error: missing ${BASIC_MMAD_EPILOGUE_TANH_REL} under ${CATLASS_DSL_DIR}" >&2
488 exit 1488 exit 1
489fi489fi
490if [[ ! -f "${CATLASS_DSL_DIR}/${CAST_MULTI_REL}" ]]; then490if [[ ! -f "${CATLASS_DSL_DIR}/${CAST_MULTI_REL}" ]]; then