已合并
[AscendNPU IR] [PlanMemory] Fix: fix planmemory level1 reuse on pong buffers #1414
SL25创建于 7月7日
[AscendNPU IR] [PlanMemory] Fix: fix planmemory level1 reuse on pong buffers #1414
已合并
共 2 个文件变更+128-13
| @@ -8,12 +8,12 @@ | |||
| 8 | 8 | ||
| 9 | 9 | ||
| 10 | 10 | ||
| 11 | |||
| 12 | 11 | ||
| 13 | 12 | ||
| 14 | 13 | ||
| 15 | 14 | ||
| 16 | 15 | ||
| 16 | |||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | 19 | ||
| @@ -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 operation | 202 | // process operation |
| @@ -1947,8 +1947,9 @@ void MemPlan::MemLifeDebugInfo(const StorageEntry *storageEntry) const { | |||
| 1947 | } | 1947 | } |
| 1948 | 1948 | ||
| 1949 | for (auto &bufferLife : storageEntry->bufferLifeVec) { | 1949 | for (auto &bufferLife : storageEntry->bufferLifeVec) { |
| 1950 | LDBG("bufferLife : " << "allocTime : " << bufferLife->allocTime | 1950 | 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 | 1955 | ||
| @@ -2255,10 +2256,14 @@ bool MemPlan::VerifyConflictStage1( | |||
| 2255 | // Multi-buffer reuse multi buffer | 2256 | // Multi-buffer reuse multi buffer |
| 2256 | 2257 | ||
| 2257 | // Multi-buffer case: require enough multibuffer entries for all buffer | 2258 | // 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-buffer | 2265 | // 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 whole | 2271 | // entry conflicts with historical records at its offset, the whole |
| 2267 | // multi-buffer reuse fails. Only when all required multibuffer entries are | 2272 | // 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() / 2 | 3213 | 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 | ||
| @@ -921,6 +921,115 @@ module { | |||
| 921 | } | 921 | } |
| 922 | } | 922 | } |
| 923 | 923 | ||
| 924 | // ----- | ||
| 925 | module { | ||
| 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 | // ----- | ||
| 960 | module { | ||
| 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 | // ----- | ||
| 997 | module { | ||
| 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 | // ----- |
| 925 | module { | 1034 | module { |
| 926 | // CHECK-LABEL: func.func @test_infer_mem_allocate_loop_conflict | 1035 | // CHECK-LABEL: func.func @test_infer_mem_allocate_loop_conflict |