skills/arm-cpu-optimize/step3-cpp-opt.md
目标:在进入 asm 前,把语义、layout、内存和调度问题先在 C++ 层解决。
优先替换能安全复用的循环:
| 代码模式 | 可考虑函数 |
|---|---|
| 大规模 GEMM | MNNPackedMatMul |
| E=1 GEMV | MNNComputeMatMulForE_1 |
| scale+bias | MNNScaleAndAddBias / MNNScaleAndAddBiasScalar |
| softmax/norm/activation | MNNSoftmax / MNNNorm / MNNExp / MNNSiLu |
| pack/unpack | 对应 gcore pack helpers |
每处替换都要检查:
dst == src 是否安全;不确定就读实现或加小测试。复杂 kernel 必须先写标量 oracle。oracle 可以是临时 debug 代码,也可以是测试中的 reference。
低 bit oracle 要显式表达:
建议分层比较:
| 输出 | 目的 |
|---|---|
| unpack int weight | 查 bit layout |
| int32 accumulator | 查 dot/smmla 分组 |
| dequant FP32 | 查 scale/zp |
| final dst | 查 postprocess |
当目标是 w2/w3、sdot、smmla、SME2 或复杂 pack/tail 时,写 C++ 模拟版再迁移 asm。
要求:
std::array 表达 lane,不依赖编译器自动向量化。simulateSdot4、simulateSmmla、unpackW3Block64。vAcc0、vInput0、vMin。简单 elementwise NEON 不强制模拟;小 reference + asm register plan 通常足够。
检查项:
new、malloc 或大 std::vector 临时缓存。不要过早做大小核特化;先让 runtime 现有线程策略和目标 kernel 路径正确。
每个小改动后优先跑 focused test:
cd build
cmake --build . -j 8
./run_test.out op/lowMemory/blockConv 0 1 4
./run_test.out op/lowMemory/HybridConv 0 1 4
./run_test.out op/lowMemory/blockConv 0 1 4 # 在 SDOT 目标设备/构建配置上复跑
./run_test.out op/lowMemory/HybridConv 0 1 4 # 在 SDOT 目标设备/构建配置上复跑
如果不是低 bit LLM kernel,替换为对应算子的最小 op test。