已合并
[AscendNPU IR] [PlanMemory] Fix: fix planmemory level1 reuse on pong buffers #1414
[AscendNPU IR] [PlanMemory] Fix: fix planmemory level1 reuse on pong buffers #1414
已合并
SL25创建于 7月7日
2 个文件变更+128-13
Mbishengir/lib/Dialect/HIVM/Transforms/PlanMemory.cpp+19-13
@@ -8,12 +8,12 @@
8 8 
9#include "bishengir/Dialect/HIVM/Transforms/PlanMemory.h"9#include "bishengir/Dialect/HIVM/Transforms/PlanMemory.h"
10#include "bishengir/Dialect/HACC/Utils/Utils.h"10#include "bishengir/Dialect/HACC/Utils/Utils.h"
11#include "bishengir/Dialect/Scope/IR/Scope.h"
12#include "bishengir/Dialect/HIVM/IR/HIVMImpl.h"11#include "bishengir/Dialect/HIVM/IR/HIVMImpl.h"
13#include "bishengir/Dialect/HIVM/Transforms/AllocToPointerCast.h"12#include "bishengir/Dialect/HIVM/Transforms/AllocToPointerCast.h"
14#include "bishengir/Dialect/HIVM/Utils/RegbaseUtils.h"13#include "bishengir/Dialect/HIVM/Utils/RegbaseUtils.h"
15#include "bishengir/Dialect/HIVM/Utils/Utils.h"14#include "bishengir/Dialect/HIVM/Utils/Utils.h"
16#include "bishengir/Dialect/MemRefExt/IR/MemRefExtImpl.h"15#include "bishengir/Dialect/MemRefExt/IR/MemRefExtImpl.h"
16#include "bishengir/Dialect/Scope/IR/Scope.h"
17#include "bishengir/Dialect/Utils/Util.h"17#include "bishengir/Dialect/Utils/Util.h"
18 18 
19#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"19#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
@@ -196,7 +196,7 @@ void MemLivenessAnalysis::RecursionIR(Region *region, Liveness live) {
196 return WalkResult::skip();196 return WalkResult::skip();
197 } else if (auto scopeOp = dyn_cast<scope::ScopeOp>(op)) {197 } else if (auto scopeOp = dyn_cast<scope::ScopeOp>(op)) {
198 RecursiveScopeOp(scopeOp, live);198 RecursiveScopeOp(scopeOp, live);
199 return WalkResult::skip(); 199 return WalkResult::skip();
200 }200 }
201 201 
202 // process operation202 // process operation
@@ -1947,8 +1947,9 @@ void MemPlan::MemLifeDebugInfo(const StorageEntry *storageEntry) const {
1947 }1947 }
1948#ifndef NDEBUG1948#ifndef NDEBUG
1949 for (auto &bufferLife : storageEntry->bufferLifeVec) {1949 for (auto &bufferLife : storageEntry->bufferLifeVec) {
1950 LDBG("bufferLife : " << "allocTime : " << bufferLife->allocTime1950 LDBG("bufferLife : "
1951 << " , freeTime : " << bufferLife->freeTime << "\n");1951 << "allocTime : " << bufferLife->allocTime
1952 << " , freeTime : " << bufferLife->freeTime << "\n");
1952 }1953 }
1953 LDBG("\n");1954 LDBG("\n");
1954#endif1955#endif
@@ -2255,10 +2256,14 @@ bool MemPlan::VerifyConflictStage1(
2255 // Multi-buffer reuse multi buffer2256 // Multi-buffer reuse multi buffer
2256 2257 
2257 // Multi-buffer case: require enough multibuffer entries for all buffer2258 // Multi-buffer case: require enough multibuffer entries for all buffer
2258 // instances.2259 // instances, and only first buffer(not other relation entries) can reuse in
2259 if (e->multiBufferNum > 1 && otherBufferEntries.size() < e->multiBufferNum) {2260 // level1.
2261 auto otherBufferEntriesSize = otherBufferEntries.size();
2262 if (e->multiBufferNum > 1 &&
2263 (otherBufferEntriesSize < e->multiBufferNum - 1 ||
2264 e->otherBufferRelationEntries.empty())) {
2260 // Not enough historical multibuffer entries to match current multi-buffer2265 // Not enough historical multibuffer entries to match current multi-buffer
2261 // requirement.2266 // requirement, or current entry is not first buffer.
2262 return true;2267 return true;
2263 }2268 }
2264 2269 
@@ -2266,7 +2271,7 @@ bool MemPlan::VerifyConflictStage1(
2266 // entry conflicts with historical records at its offset, the whole2271 // entry conflicts with historical records at its offset, the whole
2267 // multi-buffer reuse fails. Only when all required multibuffer entries are2272 // multi-buffer reuse fails. Only when all required multibuffer entries are
2268 // conflict-free can we reuse (return false).2273 // conflict-free can we reuse (return false).
2269 for (uint32_t i = 0; i < e->multiBufferNum; ++i) {2274 for (uint32_t i = 0; i < otherBufferEntriesSize; ++i) {
2270 StorageEntry *multiRelationMultiBufferEntry = otherBufferEntries[i];2275 StorageEntry *multiRelationMultiBufferEntry = otherBufferEntries[i];
2271 if (!multiRelationMultiBufferEntry) {2276 if (!multiRelationMultiBufferEntry) {
2272 return true;2277 return true;
@@ -2373,6 +2378,8 @@ void MemPlan::PlanRelationOtherBufferEntryAddress(
2373 if (StorageEntry *re = e->otherBufferRelationEntries[i])2378 if (StorageEntry *re = e->otherBufferRelationEntries[i])
2374 re->bitsOffset = otherBufferOffsets[i];2379 re->bitsOffset = otherBufferOffsets[i];
2375 }2380 }
2381 } else {
2382 llvm_unreachable("Does not support other buffer entries reuse in level1!");
2376 }2383 }
2377}2384}
2378 2385 
@@ -3024,7 +3031,7 @@ PlanMemoryPass::PlanMemoryForFuncOp(
3024 vfInplaceReuseAnalysis.getVFCallInplaceReuseInfo(funcOp));3031 vfInplaceReuseAnalysis.getVFCallInplaceReuseInfo(funcOp));
3025 memPlan.SetSyncBlockPositions(memLiveness.syncBlockPositions);3032 memPlan.SetSyncBlockPositions(memLiveness.syncBlockPositions);
3026 memPlan.SetCVMixIdReuseAllowedPairs(cvMixIdReuseAllowedPairs_);3033 memPlan.SetCVMixIdReuseAllowedPairs(cvMixIdReuseAllowedPairs_);
3027 3034 
3028 const bool isLastAttempt = attempt == kPlanRetryCount - 1;3035 const bool isLastAttempt = attempt == kPlanRetryCount - 1;
3029 if (succeeded(memPlan.plan(/*emitErrors=*/isLastAttempt))) {3036 if (succeeded(memPlan.plan(/*emitErrors=*/isLastAttempt))) {
3030 return make_optional(memPlan.GetBuffer2Offsets());3037 return make_optional(memPlan.GetBuffer2Offsets());
@@ -3125,9 +3132,8 @@ PlanMemoryPass::BuildCVReuseAllowedPairs(ModuleOp moduleOp) {
3125 // First pass: assign opIndex to every op.3132 // First pass: assign opIndex to every op.
3126 DenseMap<Operation *, int64_t> opIndex;3133 DenseMap<Operation *, int64_t> opIndex;
3127 int64_t idx = 0;3134 int64_t idx = 0;
3128 funcOp->walk<WalkOrder::PreOrder>([&](Operation *op) {3135 funcOp->walk<WalkOrder::PreOrder>(
3129 opIndex[op] = idx++;3136 [&](Operation *op) { opIndex[op] = idx++; });
3130 });
3131 // Second pass: for each cvMixId markOp, compute use range.3137 // Second pass: for each cvMixId markOp, compute use range.
3132 auto &ranges = perFuncRanges[funcOp];3138 auto &ranges = perFuncRanges[funcOp];
3133 funcOp->walk<WalkOrder::PreOrder>([&](annotation::MarkOp markOp) {3139 funcOp->walk<WalkOrder::PreOrder>([&](annotation::MarkOp markOp) {
@@ -3205,7 +3211,7 @@ PlanMemoryPass::BuildCVReuseAllowedPairs(ModuleOp moduleOp) {
3205 }3211 }
3206 }3212 }
3207 LDBG("cross-scope CV-buffer reuse: " << allowed.size() / 23213 LDBG("cross-scope CV-buffer reuse: " << allowed.size() / 2
3208 << " pair(s) allowed\n");3214 << " pair(s) allowed\n");
3209 return allowed;3215 return allowed;
3210}3216}
3211 3217 
Mbishengir/test/Dialect/HIVM/plan-memory.mlir+109-0
@@ -921,6 +921,115 @@ module {
921 }921 }
922}922}
923 923 
924// -----
925module {
926 // CHECK-LABEL: func.func @test_mem_level1_single_buffer_reuse
927 func.func @test_mem_level1_single_buffer_reuse(%src1_gm: memref<12288xf32, #hivm.address_space<gm>>,
928 %src2_gm: memref<12288xf32, #hivm.address_space<gm>>,
929 %dst1_gm: memref<12288xf32, #hivm.address_space<gm>>,
930 %dst2_gm: memref<12288xf32, #hivm.address_space<gm>>) {
931 // CHECK-NOT: memref.alloc()
932 %c0 = arith.constant 0 : index
933 %c4 = arith.constant 4 : index
934 %c16 = arith.constant 16 : index
935 scf.for %i0 = %c0 to %c16 step %c4 {
936 %src1_ub = memref.alloc() : memref<12288xf32, #hivm.address_space<ub>>
937 annotation.mark %src1_ub {hivm.multi_buffer = 4 : i32} : memref<12288xf32, #hivm.address_space<ub>>
938 %src2_ub = memref.alloc() : memref<12288xf32, #hivm.address_space<ub>>
939 %dst1_ub = memref.alloc() : memref<12288xf32, #hivm.address_space<ub>>
940 annotation.mark %dst1_ub {hivm.multi_buffer = 4 : i32} : memref<12288xf32, #hivm.address_space<ub>>
941 %dst2_ub = memref.alloc() : memref<12288xf32, #hivm.address_space<ub>>
942 hivm.hir.load ins(%src1_gm : memref<12288xf32, #hivm.address_space<gm>>)
943 outs(%src1_ub : memref<12288xf32, #hivm.address_space<ub>>)
944 hivm.hir.vadd ins(%src1_ub, %src1_ub : memref<12288xf32, #hivm.address_space<ub>>, memref<12288xf32, #hivm.address_space<ub>>)
945 outs(%dst1_ub : memref<12288xf32, #hivm.address_space<ub>>)
946 hivm.hir.store ins(%dst1_ub : memref<12288xf32,#hivm.address_space<ub>>)
947 outs(%dst1_gm: memref<12288xf32,#hivm.address_space<gm>>)
948 hivm.hir.load ins(%src2_gm : memref<12288xf32, #hivm.address_space<gm>>)
949 outs(%src2_ub : memref<12288xf32, #hivm.address_space<ub>>)
950 hivm.hir.vadd ins(%src2_ub, %src2_ub : memref<12288xf32, #hivm.address_space<ub>>, memref<12288xf32, #hivm.address_space<ub>>)
951 outs(%dst2_ub : memref<12288xf32, #hivm.address_space<ub>>)
952 hivm.hir.store ins(%dst2_ub : memref<12288xf32,#hivm.address_space<ub>>)
953 outs(%dst2_gm: memref<12288xf32,#hivm.address_space<gm>>)
954 }
955 return
956 }
957}
958 
959// -----
960module {
961 // CHECK-LABEL: func.func @test_mem_level1_equal_multi_buffers_reuse
962 func.func @test_mem_level1_equal_multi_buffers_reuse(%src1_gm: memref<9728xf32, #hivm.address_space<gm>>,
963 %src2_gm: memref<9728xf32, #hivm.address_space<gm>>,
964 %dst1_gm: memref<9728xf32, #hivm.address_space<gm>>,
965 %dst2_gm: memref<9728xf32, #hivm.address_space<gm>>) {
966 // CHECK-NOT: memref.alloc()
967 %c0 = arith.constant 0 : index
968 %c4 = arith.constant 4 : index
969 %c16 = arith.constant 16 : index
970 scf.for %i0 = %c0 to %c16 step %c4 {
971 %src1_ub = memref.alloc() : memref<9728xf32, #hivm.address_space<ub>>
972 annotation.mark %src1_ub {hivm.multi_buffer = 4 : i32} : memref<9728xf32, #hivm.address_space<ub>>
973 %src2_ub = memref.alloc() : memref<9728xf32, #hivm.address_space<ub>>
974 annotation.mark %src2_ub {hivm.multi_buffer = 4 : i32} : memref<9728xf32, #hivm.address_space<ub>>
975 %dst1_ub = memref.alloc() : memref<9728xf32, #hivm.address_space<ub>>
976 annotation.mark %dst1_ub {hivm.multi_buffer = 4 : i32} : memref<9728xf32, #hivm.address_space<ub>>
977 %dst2_ub = memref.alloc() : memref<9728xf32, #hivm.address_space<ub>>
978 annotation.mark %dst2_ub {hivm.multi_buffer = 4 : i32} : memref<9728xf32, #hivm.address_space<ub>>
979 hivm.hir.load ins(%src1_gm : memref<9728xf32, #hivm.address_space<gm>>)
980 outs(%src1_ub : memref<9728xf32, #hivm.address_space<ub>>)
981 hivm.hir.vadd ins(%src1_ub, %src1_ub : memref<9728xf32, #hivm.address_space<ub>>, memref<9728xf32, #hivm.address_space<ub>>)
982 outs(%dst1_ub : memref<9728xf32, #hivm.address_space<ub>>)
983 hivm.hir.store ins(%dst1_ub : memref<9728xf32,#hivm.address_space<ub>>)
984 outs(%dst1_gm: memref<9728xf32,#hivm.address_space<gm>>)
985 hivm.hir.load ins(%src2_gm : memref<9728xf32, #hivm.address_space<gm>>)
986 outs(%src2_ub : memref<9728xf32, #hivm.address_space<ub>>)
987 hivm.hir.vadd ins(%src2_ub, %src2_ub : memref<9728xf32, #hivm.address_space<ub>>, memref<9728xf32, #hivm.address_space<ub>>)
988 outs(%dst2_ub : memref<9728xf32, #hivm.address_space<ub>>)
989 hivm.hir.store ins(%dst2_ub : memref<9728xf32,#hivm.address_space<ub>>)
990 outs(%dst2_gm: memref<9728xf32,#hivm.address_space<gm>>)
991 }
992 return
993 }
994}
995 
996// -----
997module {
998 // CHECK-LABEL: func.func @test_mem_level1_less_multi_buffers_reuse
999 func.func @test_mem_level1_less_multi_buffers_reuse(%src1_gm: memref<9728xf32, #hivm.address_space<gm>>,
1000 %src2_gm: memref<9728xf32, #hivm.address_space<gm>>,
1001 %dst1_gm: memref<9728xf32, #hivm.address_space<gm>>,
1002 %dst2_gm: memref<9728xf32, #hivm.address_space<gm>>) {
1003 // CHECK-NOT: memref.alloc()
1004 %c0 = arith.constant 0 : index
1005 %c4 = arith.constant 4 : index
1006 %c16 = arith.constant 16 : index
1007 scf.for %i0 = %c0 to %c16 step %c4 {
1008 %src1_ub = memref.alloc() : memref<9728xf32, #hivm.address_space<ub>>
1009 annotation.mark %src1_ub {hivm.multi_buffer = 4 : i32} : memref<9728xf32, #hivm.address_space<ub>>
1010 %src2_ub = memref.alloc() : memref<9728xf32, #hivm.address_space<ub>>
1011 annotation.mark %src2_ub {hivm.multi_buffer = 2 : i32} : memref<9728xf32, #hivm.address_space<ub>>
1012 %dst1_ub = memref.alloc() : memref<9728xf32, #hivm.address_space<ub>>
1013 annotation.mark %dst1_ub {hivm.multi_buffer = 4 : i32} : memref<9728xf32, #hivm.address_space<ub>>
1014 %dst2_ub = memref.alloc() : memref<9728xf32, #hivm.address_space<ub>>
1015 annotation.mark %dst2_ub {hivm.multi_buffer = 2 : i32} : memref<9728xf32, #hivm.address_space<ub>>
1016 hivm.hir.load ins(%src1_gm : memref<9728xf32, #hivm.address_space<gm>>)
1017 outs(%src1_ub : memref<9728xf32, #hivm.address_space<ub>>)
1018 hivm.hir.vadd ins(%src1_ub, %src1_ub : memref<9728xf32, #hivm.address_space<ub>>, memref<9728xf32, #hivm.address_space<ub>>)
1019 outs(%dst1_ub : memref<9728xf32, #hivm.address_space<ub>>)
1020 hivm.hir.store ins(%dst1_ub : memref<9728xf32,#hivm.address_space<ub>>)
1021 outs(%dst1_gm: memref<9728xf32,#hivm.address_space<gm>>)
1022 hivm.hir.load ins(%src2_gm : memref<9728xf32, #hivm.address_space<gm>>)
1023 outs(%src2_ub : memref<9728xf32, #hivm.address_space<ub>>)
1024 hivm.hir.vadd ins(%src2_ub, %src2_ub : memref<9728xf32, #hivm.address_space<ub>>, memref<9728xf32, #hivm.address_space<ub>>)
1025 outs(%dst2_ub : memref<9728xf32, #hivm.address_space<ub>>)
1026 hivm.hir.store ins(%dst2_ub : memref<9728xf32,#hivm.address_space<ub>>)
1027 outs(%dst2_gm: memref<9728xf32,#hivm.address_space<gm>>)
1028 }
1029 return
1030 }
1031}
1032 
924// -----1033// -----
925module {1034module {
926 // CHECK-LABEL: func.func @test_infer_mem_allocate_loop_conflict1035 // CHECK-LABEL: func.func @test_infer_mem_allocate_loop_conflict