已合并
fix(costmodel): fix a5 vf costmodel implementation #1700
fix(costmodel): fix a5 vf costmodel implementation #1700
已合并
海王星创建于 9月17日
共 75 个文件变更+7-9438
@@ -1,121 +0,0 @@
1- 
2-set(_pto_a5_self_dir "${CMAKE_CURRENT_LIST_DIR}")
3-set(_pto_a5_repo_dir "${CMAKE_CURRENT_LIST_DIR}/..")
4- 
5-function(_pto_a5_build_vfsim)
6- if(TARGET pto_a5_vfsim)
7- return()
8- endif()
9- set(_vfsim_dir "${_pto_a5_repo_dir}/include/pto/costmodel/a5/VfSim")
10- find_package(Python3 COMPONENTS Interpreter REQUIRED)
11- execute_process(
12- COMMAND ${Python3_EXECUTABLE}
13- "${_pto_a5_repo_dir}/include/pto/costmodel/a5/formula_costmodel/gen_formula_params_header.py"
14- WORKING_DIRECTORY "${_pto_a5_repo_dir}"
15- RESULT_VARIABLE _a5_formula_param_gen_result)
16- if(NOT _a5_formula_param_gen_result EQUAL 0)
17- message(FATAL_ERROR "a5_vf_mock: failed to generate a5 formula_params_generated.hpp")
18- endif()
19- execute_process(
20- COMMAND ${Python3_EXECUTABLE} "${_vfsim_dir}/gen_vfsim_params_header.py"
21- WORKING_DIRECTORY "${_pto_a5_repo_dir}"
22- RESULT_VARIABLE _vfsim_param_gen_result)
23- if(NOT _vfsim_param_gen_result EQUAL 0)
24- message(FATAL_ERROR "a5_vf_mock: failed to generate VfSimParamsGenerated.h")
25- endif()
26- add_library(pto_a5_vfsim STATIC
27- ${_vfsim_dir}/VfInfo.cpp
28- ${_vfsim_dir}/ParamDB.cpp
29- ${_vfsim_dir}/ISATraits.cpp
30- ${_vfsim_dir}/ProgramAnalysis.cpp
31- ${_vfsim_dir}/ProgramCanonicalization.cpp
32- ${_vfsim_dir}/ProgramVregLiveRangeNormalization.cpp
33- ${_vfsim_dir}/ProgramFlatten.cpp
34- ${_vfsim_dir}/IFU.cpp
35- ${_vfsim_dir}/IDU.cpp
36- ${_vfsim_dir}/OOO.cpp
37- ${_vfsim_dir}/SimulatorRunner.cpp
38- ${_vfsim_dir}/VfSimCostModel.cpp)
39- target_include_directories(pto_a5_vfsim PUBLIC "${_pto_a5_repo_dir}/include")
40- target_compile_features(pto_a5_vfsim PUBLIC cxx_std_20)
41- target_compile_definitions(pto_a5_vfsim PRIVATE PTO_VFSIM_SOURCE_ROOT="${_vfsim_dir}")
42-endfunction()
43- 
44-macro(_pto_a5_find_llvm)
45- if(NOT PTO_A5_LLVM_CONFIG)
46- if(DEFINED ENV{LLVM_CONFIG} AND EXISTS "$ENV{LLVM_CONFIG}")
47- set(PTO_A5_LLVM_CONFIG "$ENV{LLVM_CONFIG}")
48- else()
49- file(GLOB _pto_a5_bindirs /usr/lib/llvm-*/bin
50- /usr/local/opt/llvm@*/bin /usr/local/opt/llvm/bin)
51- find_program(PTO_A5_LLVM_CONFIG
52- NAMES llvm-config llvm-config-20 llvm-config-19 llvm-config-18
53- llvm-config-17 llvm-config-16 llvm-config-15 llvm-config-14
54- PATHS ${_pto_a5_bindirs} /usr/local/bin /usr/bin)
55- endif()
56- endif()
57- if(NOT PTO_A5_LLVM_CONFIG)
58- message(FATAL_ERROR "a5_vf_mock: llvm-config not found. Mac: brew install llvm@18; "
59- "Linux: sudo apt install clang-N llvm-N-dev (N>=14), or set LLVM_CONFIG env.")
60- endif()
61- execute_process(COMMAND ${PTO_A5_LLVM_CONFIG} --version
62- OUTPUT_VARIABLE PTO_A5_LLVM_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
63- execute_process(COMMAND ${PTO_A5_LLVM_CONFIG} --bindir
64- OUTPUT_VARIABLE PTO_A5_LLVM_BINDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
65- string(REGEX MATCH "^([0-9]+)" PTO_A5_LLVM_MAJOR "${PTO_A5_LLVM_VERSION}")
66- if(NOT PTO_A5_CLANGXX OR NOT EXISTS "${PTO_A5_CLANGXX}")
67- unset(PTO_A5_CLANGXX CACHE)
68- find_program(PTO_A5_CLANGXX NAMES clang++-${PTO_A5_LLVM_MAJOR} clang++
69- PATHS ${PTO_A5_LLVM_BINDIR} /usr/bin /usr/local/bin NO_DEFAULT_PATH)
70- if(NOT PTO_A5_CLANGXX)
71- find_program(PTO_A5_CLANGXX NAMES clang++-${PTO_A5_LLVM_MAJOR} clang++)
72- endif()
73- endif()
74- if(NOT PTO_A5_CLANGXX)
75- message(FATAL_ERROR "a5_vf_mock: matching clang++ for LLVM ${PTO_A5_LLVM_MAJOR} not found")
76- endif()
77- execute_process(COMMAND ${PTO_A5_LLVM_CONFIG} --cxxflags
78- OUTPUT_VARIABLE PTO_A5_LLVM_CXXFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
79- separate_arguments(PTO_A5_LLVM_CXXFLAGS NATIVE_COMMAND "${PTO_A5_LLVM_CXXFLAGS}")
80- message(STATUS "a5_vf_mock: LLVM ${PTO_A5_LLVM_VERSION} (${PTO_A5_LLVM_CONFIG})")
81-endmacro()
82- 
83-macro(_pto_a5_build_pass)
84- if(NOT TARGET PtoLoopTracePass)
85- _pto_a5_find_llvm()
86- set(_pass_src "${_pto_a5_self_dir}/../include/pto/costmodel/a5/PtoLoopTracePass.cpp")
87- add_library(PtoLoopTracePass MODULE ${_pass_src})
88- target_compile_options(PtoLoopTracePass PRIVATE ${PTO_A5_LLVM_CXXFLAGS}
89- -Wno-unused-command-line-argument -Wno-unknown-warning-option)
90- if(APPLE)
91- file(GLOB _sdks "/Library/Developer/CommandLineTools/SDKs/MacOSX*.sdk")
92- set(_sdk "")
93- foreach(s IN LISTS _sdks)
94- if(EXISTS "${s}/usr/include/c++/v1" AND EXISTS "${s}/usr/lib/libc++.tbd")
95- get_filename_component(_n "${s}" NAME)
96- string(REGEX MATCH "MacOSX([0-9]+\\.[0-9]+)\\.sdk" _ "${_n}")
97- if(CMAKE_MATCH_1 AND CMAKE_MATCH_1 VERSION_LESS 16)
98- set(_sdk "${s}")
99- endif()
100- endif()
101- endforeach()
102- if(_sdk)
103- target_compile_options(PtoLoopTracePass PRIVATE -isysroot ${_sdk})
104- target_link_options(PtoLoopTracePass PRIVATE -undefined dynamic_lookup -nostdlib++
105- -Wl,-syslibroot,${_sdk})
106- else()
107- target_link_options(PtoLoopTracePass PRIVATE -undefined dynamic_lookup -nostdlib++)
108- endif()
109- endif()
110- endif()
111-endmacro()
112- 
113-function(target_enable_a5_vf_mock target)
114- _pto_a5_build_pass()
115- _pto_a5_build_vfsim()
116- add_dependencies(${target} PtoLoopTracePass)
117- target_link_libraries(${target} PRIVATE pto_a5_vfsim)
118- target_compile_options(${target} PRIVATE
119- -O0 -g -fpass-plugin=$<TARGET_FILE:PtoLoopTracePass>)
120- message(STATUS "a5_vf_mock: ${target} enabled pass instrumentation (-O0 -g -fpass-plugin)")
121-endfunction()
@@ -1,278 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#include "llvm/ADT/APInt.h"
11-#include "llvm/ADT/Hashing.h"
12-#include "llvm/ADT/StringRef.h"
13-#include "llvm/ADT/Twine.h"
14-#include "llvm/Analysis/LoopInfo.h"
15-#include "llvm/IR/Dominators.h"
16-#include "llvm/IR/Constants.h"
17-#include "llvm/IR/DebugInfoMetadata.h"
18-#include "llvm/IR/DebugLoc.h"
19-#include "llvm/IR/DerivedTypes.h"
20-#include "llvm/IR/Function.h"
21-#include "llvm/IR/IRBuilder.h"
22-#include "llvm/IR/Instructions.h"
23-#include "llvm/IR/Module.h"
24-#include "llvm/Passes/PassBuilder.h"
25-#include "llvm/Passes/PassPlugin.h"
26-#include "llvm/Support/Compiler.h"
27-#include "llvm/Support/raw_ostream.h"
28-#include "llvm/Transforms/Utils/BasicBlockUtils.h"
29-#include "llvm/Transforms/Utils/LoopUtils.h" // formDedicatedExitBlocks
30- 
31-#include <cstring>
32-#include <string>
33-#include <vector>
34- 
35-using namespace llvm;
36- 
37-namespace {
38- 
39-static bool nameStartsWith(StringRef s, const char* p)
40-{
41- size_t n = std::strlen(p);
42- return s.size() >= n && std::memcmp(s.data(), p, n) == 0;
43-}
44-static PointerType* i8PtrTy(LLVMContext& C) { return PointerType::getUnqual(Type::getInt8Ty(C)); }
45- 
46-static FunctionCallee getOrInsertLoopEnter(Module& M)
47-{
48- LLVMContext& C = M.getContext();
49- auto* i64 = Type::getInt64Ty(C);
50- auto* i8p = i8PtrTy(C);
51- auto* i32 = Type::getInt32Ty(C);
52- return M.getOrInsertFunction(
53- "__pto_trace_loop_enter", FunctionType::get(Type::getVoidTy(C), {i64, i8p, i32, i32}, false));
54-}
55-static FunctionCallee getOrInsertLoopIter(Module& M)
56-{
57- LLVMContext& C = M.getContext();
58- return M.getOrInsertFunction(
59- "__pto_trace_loop_iter", FunctionType::get(Type::getVoidTy(C), {Type::getInt64Ty(C)}, false));
60-}
61-static FunctionCallee getOrInsertLoopExit(Module& M)
62-{
63- LLVMContext& C = M.getContext();
64- return M.getOrInsertFunction(
65- "__pto_trace_loop_exit", FunctionType::get(Type::getVoidTy(C), {Type::getInt64Ty(C)}, false));
66-}
67- 
68-static DebugLoc getLoopDebugLoc(Loop* L)
69-{
70- if (DebugLoc loc = L->getStartLoc())
71- return loc;
72- for (Instruction& I : *L->getHeader())
73- if (I.getDebugLoc())
74- return I.getDebugLoc();
75- return DebugLoc();
76-}
77- 
78-static uint64_t computeLoopId(Function& F, Loop* L)
79-{
80- DebugLoc loc = getLoopDebugLoc(L);
81- std::string key;
82- raw_string_ostream os(key);
83- os << F.getName() << "|";
84- if (loc) {
85- if (auto* scope = dyn_cast_or_null<DILocalScope>(loc.getScope()))
86- if (auto* file = scope->getFile())
87- os << file->getFilename() << "|";
88- os << loc.getLine() << ":" << loc.getCol();
89- }
90- os.flush();
91- return static_cast<uint64_t>(hash_value(StringRef(key)));
92-}
93- 
94-struct LoopWork {
95- uint64_t loopId;
96- BasicBlock* preheader;
97- BasicBlock* header;
98- std::string file;
99- int line;
100- int col;
101- std::vector<BasicBlock*> exitBlocks;
102-};
103- 
104-static bool isScopeCtorCall(const CallBase* call)
105-{
106- const Function* callee = call->getCalledFunction();
107- return callee != nullptr && callee->getName().contains("ScopeSentinelC");
108-}
109- 
110-static std::vector<const Instruction*> collectScopeEnters(Function& F)
111-{
112- std::vector<const Instruction*> scopeEnters;
113- for (BasicBlock& BB : F)
114- for (Instruction& I : BB)
115- if (const auto* call = dyn_cast<CallBase>(&I))
116- if (isScopeCtorCall(call))
117- scopeEnters.push_back(&I);
118- return scopeEnters;
119-}
120- 
121-template <class InScopeFn>
122-static void collectLoopInScope(Loop* L, Function& F, std::vector<LoopWork>& out, InScopeFn&& inScope)
123-{
124- for (Loop* sub : L->getSubLoops())
125- collectLoopInScope(sub, F, out, inScope);
126- 
127- if (!inScope(L))
128- return;
129- 
130- BasicBlock* pre = L->getLoopPreheader();
131- DebugLoc loc = getLoopDebugLoc(L);
132- if (!pre) {
133- errs() << "[PtoLoopTrace] WARN: loop without preheader skipped (" << F.getName() << ")\n";
134- return;
135- }
136- if (!loc) {
137- errs() << "[PtoLoopTrace] WARN: loop without DebugLoc skipped (" << F.getName() << ")\n";
138- return;
139- }
140- 
141- LoopWork w;
142- w.loopId = computeLoopId(F, L);
143- w.preheader = pre;
144- w.header = L->getHeader();
145- if (auto* scope = dyn_cast_or_null<DILocalScope>(loc.getScope()))
146- if (auto* file = scope->getFile())
147- w.file = file->getFilename().str();
148- w.line = static_cast<int>(loc.getLine());
149- w.col = static_cast<int>(loc.getCol());
150- 
151- if (!L->hasDedicatedExits()) {
152- errs() << "[PtoLoopTrace] WARN: loop without dedicated exits skipped (" << F.getName() << ")\n";
153- return;
154- }
155- SmallVector<BasicBlock*, 4> exitBlks;
156- L->getUniqueExitBlocks(exitBlks);
157- for (BasicBlock* eb : exitBlks)
158- w.exitBlocks.push_back(eb);
159- out.push_back(std::move(w));
160-}
161- 
162-template <class InScopeFn>
163-static bool formDedicatedExitsForScopedLoops(LoopInfo& LI, DominatorTree& DT, InScopeFn&& loopInScope)
164-{
165- bool cfgChanged = false;
166- for (Loop* L : LI) {
167- SmallVector<Loop*, 8> nest;
168- nest.push_back(L);
169- for (size_t i = 0; i < nest.size(); ++i)
170- for (Loop* sub : nest[i]->getSubLoops())
171- nest.push_back(sub);
172- for (Loop* cur : nest)
173- if (loopInScope(cur))
174- cfgChanged |= formDedicatedExitBlocks(
175- cur, &DT, &LI,
176- /*MSSAU=*/nullptr,
177- /*PreserveLCSSA=*/false);
178- }
179- return cfgChanged;
180-}
181- 
182-static void insertLoopEnterAndIter(LoopWork& w, LLVMContext& C, FunctionCallee enterFn, FunctionCallee iterFn)
183-{
184- ConstantInt* loopIdC = ConstantInt::get(C, APInt(64, w.loopId));
185- IRBuilder<> enterBuilder(w.preheader->getTerminator());
186- Value* filePtr = enterBuilder.CreateGlobalStringPtr(w.file.empty() ? StringRef("") : StringRef(w.file));
187- enterBuilder.CreateCall(
188- enterFn, {loopIdC, filePtr, ConstantInt::get(C, APInt(32, static_cast<uint64_t>(w.line))),
189- ConstantInt::get(C, APInt(32, static_cast<uint64_t>(w.col)))});
190- 
191- IRBuilder<> iterBuilder(w.header, w.header->getFirstInsertionPt());
192- iterBuilder.CreateCall(iterFn, {loopIdC});
193-}
194- 
195-static void insertLoopExits(LoopWork& w, LLVMContext& C, FunctionCallee exitFn)
196-{
197- ConstantInt* loopIdC = ConstantInt::get(C, APInt(64, w.loopId));
198- for (BasicBlock* eb : w.exitBlocks) {
199- IRBuilder<> b(eb, eb->getFirstInsertionPt());
200- b.CreateCall(exitFn, {loopIdC});
201- }
202-}
203- 
204-struct PtoLoopTracePass : PassInfoMixin<PtoLoopTracePass> {
205- PreservedAnalyses run(Function& F, FunctionAnalysisManager& FAM)
206- {
207- if (F.isDeclaration())
208- return PreservedAnalyses::all();
209- 
210- Module& M = *F.getParent();
211- LoopInfo& LI = FAM.getResult<LoopAnalysis>(F);
212- DominatorTree& DT = FAM.getResult<DominatorTreeAnalysis>(F);
213- 
214- std::vector<const Instruction*> scopeEnters = collectScopeEnters(F);
215- 
216- const bool isDemo = nameStartsWith(F.getName(), "__pto_demo_");
217- if (scopeEnters.empty() && !isDemo) {
218- return PreservedAnalyses::all();
219- }
220- 
221- auto loopInScope = [&](Loop* L) -> bool {
222- if (isDemo)
223- return true;
224- BasicBlock* h = L->getHeader();
225- for (const Instruction* en : scopeEnters)
226- if (DT.dominates(en, &*h->getFirstInsertionPt()))
227- return true;
228- return false;
229- };
230- 
231- bool cfgChanged = formDedicatedExitsForScopedLoops(LI, DT, loopInScope);
232- if (cfgChanged)
233- DT.recalculate(F);
234- 
235- std::vector<LoopWork> work;
236- for (Loop* L : LI)
237- collectLoopInScope(L, F, work, loopInScope);
238- if (work.empty())
239- return PreservedAnalyses::all();
240- 
241- FunctionCallee enterFn = getOrInsertLoopEnter(M);
242- FunctionCallee iterFn = getOrInsertLoopIter(M);
243- FunctionCallee exitFn = getOrInsertLoopExit(M);
244- LLVMContext& C = M.getContext();
245- 
246- bool changed = false;
247- for (LoopWork& w : work) {
248- insertLoopEnterAndIter(w, C, enterFn, iterFn);
249- changed = true;
250- }
251- 
252- for (LoopWork& w : work) {
253- insertLoopExits(w, C, exitFn);
254- }
255- 
256- return changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
257- }
258- 
259- static bool isRequired() { return true; }
260-};
261- 
262-} // namespace
263- 
264-extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo()
265-{
266- return {LLVM_PLUGIN_API_VERSION, "PtoLoopTrace", LLVM_VERSION_STRING, [](PassBuilder& PB) {
267- PB.registerPipelineParsingCallback(
268- [](StringRef Name, FunctionPassManager& FPM, ArrayRef<PassBuilder::PipelineElement>) {
269- if (Name != "pto-loop-trace")
270- return false;
271- FPM.addPass(PtoLoopTracePass());
272- return true;
273- });
274- PB.registerPipelineStartEPCallback([](ModulePassManager& MPM, OptimizationLevel) {
275- MPM.addPass(createModuleToFunctionPassAdaptor(PtoLoopTracePass()));
276- });
277- }};
278-}
@@ -1,436 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#include "pto/costmodel/a5/VfSim/IDU.h"
11- 
12-#include "pto/costmodel/a5/VfSim/ISATraits.h"
13- 
14-#include <algorithm>
15-#include <sstream>
16-#include <stdexcept>
17-#include <utility>
18- 
19-namespace vfsim {
20-namespace {
21- 
22-std::string joinInts(const std::vector<int64_t>& values)
23-{
24- std::ostringstream oss;
25- for (size_t i = 0; i < values.size(); ++i) {
26- if (i)
27- oss << ',';
28- oss << values[i];
29- }
30- return oss.str();
31-}
32- 
33-} // namespace
34- 
35-IDU::IDU(
36- const UarchConfig& uarch, const ParamDB& db, ProgramAnalysis::ParamMap params, std::vector<int64_t> loopBounds,
37- int64_t totalTopBlocks, std::unordered_map<int, std::vector<int64_t>> topBlockLoopBounds, std::string dtype,
38- std::unordered_map<std::string, ValueInfo> values)
39- : db_(db),
40- dtype_(std::move(dtype)),
41- analysis_(std::move(params), std::move(values)),
42- loopBounds_(std::move(loopBounds)),
43- totalTopBlocks_(totalTopBlocks),
44- topBlockLoopBounds_(std::move(topBlockLoopBounds))
45-{
46- windowWidth_ = uarch.iduWindowWidth;
47- issueWidth_ = uarch.iduIssueWidth;
48- theoreticalLimitMode_ = false;
49- theoreticalLimitVloopOnly_ = false;
50- vfStartupCost_ = db_.isaDefaults().vfStartupCost;
51- iduDispatchStartAdvance_ = uarch.iduDispatchStartAdvance;
52- vloopToDispatchDelay_ = uarch.vloopToDispatchDelay;
53- initialTopBlockVloopStartCycle_ = uarch.initialTopBlockVloopStartCycle;
54- nestedVloopInitialStartGap_ = uarch.nestedVloopInitialStartGap;
55- loop1MinFeedbackGap_ = uarch.loop1MinFeedbackGap;
56- innermostIterDispatchStride_ = uarch.innermostIterDispatchStride;
57- globalShqPregGate_ = uarch.globalShqPregGate;
58- initVloopStarts();
59-}
60- 
61-bool IDU::canAccept() const
62-{
63- if (theoreticalLimitMode_)
64- return true;
65- return static_cast<int64_t>(window_.size()) < windowWidth_;
66-}
67- 
68-void IDU::accept(const DynamicInst& inst)
69-{
70- if (theoreticalLimitMode_ || static_cast<int64_t>(window_.size()) < windowWidth_)
71- window_.push_back(inst);
72-}
73- 
74-void IDU::setTopBlockVloop(int64_t topBlockId, int64_t startCycle)
75-{
76- if (topBlockVloopStart_.count(topBlockId))
77- return;
78- topBlockVloopStart_[topBlockId] = startCycle;
79- topBlockBodyOpenTime_[topBlockId] = startCycle + vloopToDispatchDelay_;
80- vloopTrace_.push_back(VloopTraceRecord{topBlockId, "top_block", {}, startCycle});
81-}
82- 
83-void IDU::initTopBlockNestedStarts(int64_t topBlockId, int64_t topVloopStart)
84-{
85- const auto it = topBlockLoopBounds_.find(static_cast<int>(topBlockId));
86- const std::vector<int64_t>& bounds = it == topBlockLoopBounds_.end() ? loopBounds_ : it->second;
87- const int64_t depth = static_cast<int64_t>(bounds.size());
88- if (depth <= 0)
89- return;
90- 
91- setTopBlockVloop(topBlockId, topVloopStart);
92- if (depth >= 1) {
93- const std::string key0 = makeKey(topBlockId, "loop0", {});
94- vloopStart_[key0] = topVloopStart;
95- bodyOpenTime_[key0] = topVloopStart + vloopToDispatchDelay_;
96- }
97- if (depth >= 2 && bounds[0] > 0) {
98- const std::string key1 = makeKey(topBlockId, "loop1", {0});
99- vloopStart_[key1] = topVloopStart + nestedVloopInitialStartGap_;
100- bodyOpenTime_[key1] = vloopStart_[key1] + vloopToDispatchDelay_;
101- }
102- if (depth >= 3 && bounds[0] > 0 && bounds[1] > 0) {
103- const std::string key2 = makeKey(topBlockId, "loop2", {0, 0});
104- vloopStart_[key2] = topVloopStart + 2 * nestedVloopInitialStartGap_;
105- bodyOpenTime_[key2] = vloopStart_[key2] + vloopToDispatchDelay_;
106- }
107-}
108- 
109-void IDU::initVloopStarts()
110-{
111- if (totalTopBlocks_ <= 0)
112- return;
113- setTopBlockVloop(0, initialTopBlockVloopStartCycle_);
114- initTopBlockNestedStarts(0, initialTopBlockVloopStartCycle_);
115-}
116- 
117-std::string IDU::makeKey(int64_t topBlockId, const std::string& loopId, const std::vector<int64_t>& iters) const
118-{
119- return std::to_string(topBlockId) + "|" + loopId + "|" + joinInts(iters);
120-}
121- 
122-std::optional<std::string> IDU::normalizeBlockKey(
123- const std::pair<std::string, std::vector<int64_t>>& raw, int64_t topBlockId) const
124-{
125- if (raw.first.empty())
126- return std::nullopt;
127- return makeKey(topBlockId, raw.first, raw.second);
128-}
129- 
130-std::optional<std::string> IDU::currentInnerBlockKey(const DynamicInst& inst) const
131-{
132- const int64_t topBlockId = inst.topBlockId;
133- const auto& bk = inst.blockKeyByLevel;
134- if (!bk.empty()) {
135- return normalizeBlockKey(bk.back(), topBlockId);
136- }
137- 
138- const auto& iterStack = inst.iterStack;
139- const int64_t depth =
140- std::min<int64_t>(static_cast<int64_t>(loopBounds_.size()), static_cast<int64_t>(inst.loopDepth));
141- if (depth <= 0)
142- return std::nullopt;
143- if (depth == 1)
144- return makeKey(topBlockId, "loop0", {});
145- if (depth == 2 && iterStack.size() >= 1)
146- return makeKey(topBlockId, "loop1", {iterStack[0]});
147- if (depth >= 3 && iterStack.size() >= 2)
148- return makeKey(topBlockId, "loop2", {iterStack[0], iterStack[1]});
149- return std::nullopt;
150-}
151- 
152-bool IDU::isLastInstOfTopBlock(const DynamicInst& inst) const
153-{
154- if (inst.blockEndLevels.empty())
155- return false;
156- return inst.isLastInTopBlock;
157-}
158- 
159-const std::vector<int64_t>& IDU::loopBoundsForTopBlock(int64_t topBlockId) const
160-{
161- const auto it = topBlockLoopBounds_.find(static_cast<int>(topBlockId));
162- return it == topBlockLoopBounds_.end() ? loopBounds_ : it->second;
163-}
164- 
165-bool IDU::hasBlockEndLevel(const DynamicInst& inst, int64_t level) const
166-{
167- return std::find(inst.blockEndLevels.begin(), inst.blockEndLevels.end(), level) != inst.blockEndLevels.end();
168-}
169- 
170-void IDU::triggerNextTopBlock(const DynamicInst& inst, int64_t cycle)
171-{
172- if (!inst.isLastInTopBlock)
173- return;
174- const int64_t nextTop = inst.topBlockId + 1;
175- if (nextTop >= totalTopBlocks_ || topBlockVloopStart_.count(nextTop))
176- return;
177- setTopBlockVloop(nextTop, cycle);
178- initTopBlockNestedStarts(nextTop, cycle);
179-}
180- 
181-int64_t IDU::lastDispatchOrCycle(const std::string& key, int64_t cycle) const
182-{
183- const auto it = lastDispatchTime_.find(key);
184- return it == lastDispatchTime_.end() ? cycle : it->second;
185-}
186- 
187-void IDU::openLoopBody(const std::string& key, int64_t startCycle)
188-{
189- vloopStart_[key] = startCycle;
190- bodyOpenTime_[key] = startCycle + vloopToDispatchDelay_;
191-}
192- 
193-std::optional<int64_t> IDU::nextLoop1Start(
194- const DynamicInst& inst, const std::vector<int64_t>& bounds, int64_t cycle) const
195-{
196- if (!hasBlockEndLevel(inst, 1) || inst.iterStack.empty())
197- return std::nullopt;
198- const int64_t topBlockId = inst.topBlockId;
199- const int64_t i = inst.iterStack[0];
200- const std::string curKey = makeKey(topBlockId, "loop1", {i});
201- const int64_t endCy = lastDispatchOrCycle(curKey, cycle);
202- if (i + 1 >= bounds[0])
203- return std::nullopt;
204- const auto startIt = vloopStart_.find(curKey);
205- const int64_t prevStart = startIt == vloopStart_.end() ? endCy : startIt->second;
206- return std::max<int64_t>(endCy, prevStart + loop1MinFeedbackGap_);
207-}
208- 
209-void IDU::triggerDepth2Vloops(const DynamicInst& inst, const std::vector<int64_t>& bounds, int64_t cycle)
210-{
211- const auto nextStart = nextLoop1Start(inst, bounds, cycle);
212- if (!nextStart.has_value())
213- return;
214- const int64_t topBlockId = inst.topBlockId;
215- const int64_t i = inst.iterStack[0];
216- const std::string nextKey = makeKey(topBlockId, "loop1", {i + 1});
217- openLoopBody(nextKey, *nextStart);
218- vloopTrace_.push_back(VloopTraceRecord{topBlockId, "loop1", {i + 1}, *nextStart});
219-}
220- 
221-void IDU::triggerDepth3InnerVloops(const DynamicInst& inst, const std::vector<int64_t>& bounds, int64_t cycle)
222-{
223- if (!hasBlockEndLevel(inst, 2) || inst.iterStack.size() < 2)
224- return;
225- const int64_t topBlockId = inst.topBlockId;
226- const int64_t i = inst.iterStack[0];
227- const int64_t j = inst.iterStack[1];
228- const std::string curKey = makeKey(topBlockId, "loop2", {i, j});
229- const int64_t endCy = lastDispatchOrCycle(curKey, cycle);
230- if (j + 1 >= bounds[1])
231- return;
232- const std::string nextKey = makeKey(topBlockId, "loop2", {i, j + 1});
233- openLoopBody(nextKey, endCy);
234- vloopTrace_.push_back(VloopTraceRecord{topBlockId, "loop2", {i, j + 1}, endCy});
235-}
236- 
237-void IDU::triggerDepth3OuterVloops(const DynamicInst& inst, const std::vector<int64_t>& bounds, int64_t cycle)
238-{
239- const auto nextStart = nextLoop1Start(inst, bounds, cycle);
240- if (!nextStart.has_value())
241- return;
242- const int64_t topBlockId = inst.topBlockId;
243- const int64_t i = inst.iterStack[0];
244- openLoopBody(makeKey(topBlockId, "loop1", {i + 1}), *nextStart);
245- vloopTrace_.push_back(VloopTraceRecord{topBlockId, "loop1", {i + 1}, *nextStart});
246- if (bounds[1] <= 0)
247- return;
248- const int64_t childStart = *nextStart + nestedVloopInitialStartGap_;
249- openLoopBody(makeKey(topBlockId, "loop2", {i + 1, 0}), childStart);
250- vloopTrace_.push_back(VloopTraceRecord{topBlockId, "loop2", {i + 1, 0}, childStart});
251-}
252- 
253-void IDU::updateLastDispatch(const DynamicInst& inst, int64_t cycle)
254-{
255- const int64_t topBlockId = inst.topBlockId;
256- const auto& bk = inst.blockKeyByLevel;
257- if (!bk.empty()) {
258- for (const auto& raw : bk) {
259- if (auto key = normalizeBlockKey(raw, topBlockId))
260- lastDispatchTime_[*key] = cycle;
261- }
262- return;
263- }
264- 
265- const auto& iterStack = inst.iterStack;
266- const int64_t depth = static_cast<int64_t>(inst.loopDepth);
267- if (depth == 1) {
268- lastDispatchTime_[makeKey(topBlockId, "loop0", {})] = cycle;
269- } else if (depth == 2 && iterStack.size() >= 1) {
270- lastDispatchTime_[makeKey(topBlockId, "loop1", {iterStack[0]})] = cycle;
271- } else if (depth >= 3 && iterStack.size() >= 2) {
272- lastDispatchTime_[makeKey(topBlockId, "loop2", {iterStack[0], iterStack[1]})] = cycle;
273- lastDispatchTime_[makeKey(topBlockId, "loop1", {iterStack[0]})] = cycle;
274- lastDispatchTime_[makeKey(topBlockId, "loop0", {})] = cycle;
275- }
276-}
277- 
278-void IDU::triggerNextVloops(const DynamicInst& inst, int64_t cycle)
279-{
280- const int64_t topBlockId = inst.topBlockId;
281- const std::vector<int64_t>& bounds = loopBoundsForTopBlock(topBlockId);
282- const int64_t depth = static_cast<int64_t>(bounds.size());
283- 
284- triggerNextTopBlock(inst, cycle);
285- 
286- if (depth <= 0 || inst.blockEndLevels.empty())
287- return;
288- 
289- if (depth == 1)
290- return;
291- if (depth == 2) {
292- triggerDepth2Vloops(inst, bounds, cycle);
293- return;
294- }
295- if (depth == 3) {
296- triggerDepth3InnerVloops(inst, bounds, cycle);
297- triggerDepth3OuterVloops(inst, bounds, cycle);
298- }
299-}
300- 
301-IDU::DispatchResources IDU::makeDispatchResources(const IDUDispatchBudget& budget) const
302-{
303- constexpr int64_t kUnlimited = 1LL << 60;
304- if (budget.theoreticalLimitMode) {
305- return DispatchResources{kUnlimited, kUnlimited, kUnlimited, kUnlimited, static_cast<int64_t>(window_.size())};
306- }
307- return DispatchResources{budget.freePreg, budget.freeShqQueue, budget.freeLsq, budget.freeShq, budget.issueBudget};
308-}
309- 
310-bool IDU::hasInitialDispatchCredit(const DispatchResources& resources) const
311-{
312- if (resources.shqQueueFree <= 0 && resources.lsqFree <= 0)
313- return false;
314- return !globalShqPregGate_ || (resources.credits > 0 && resources.shqFree > 0);
315-}
316- 
317-bool IDU::isVloopDispatchOpen(const DynamicInst& inst, int64_t cycle, const IDUDispatchBudget& budget)
318-{
319- const auto topOpenIt = topBlockBodyOpenTime_.find(inst.topBlockId);
320- if (topOpenIt == topBlockBodyOpenTime_.end() || cycle < topOpenIt->second)
321- return false;
322- 
323- const auto innerKey = currentInnerBlockKey(inst);
324- if (!budget.theoreticalLimitVloopOnly && innerKey) {
325- const auto openIt = bodyOpenTime_.find(*innerKey);
326- if (openIt == bodyOpenTime_.end() || cycle < openIt->second)
327- return false;
328- }
329- if (budget.theoreticalLimitMode || budget.theoreticalLimitVloopOnly || !innerKey) {
330- return true;
331- }
332- 
333- const int64_t iterId = inst.iterStack.empty() ? 0 : inst.iterStack.back();
334- if (iterId == 0 && !blockBaseCycle_.count(*innerKey))
335- blockBaseCycle_[*innerKey] = cycle;
336- const auto baseIt = blockBaseCycle_.find(*innerKey);
337- if (baseIt == blockBaseCycle_.end())
338- return false;
339- return cycle >= baseIt->second + iterId * innermostIterDispatchStride_;
340-}
341- 
342-bool IDU::hasQueueResource(const DynamicInst& inst, const std::string& form, const DispatchResources& resources) const
343-{
344- if (isLoadOp(db_, inst.op, form))
345- return resources.lsqFree > 0;
346- if (isStoreOp(db_, inst.op, form))
347- return resources.lsqFree > 0 && resources.shqFree > 0;
348- return resources.shqQueueFree > 0 && resources.shqFree > 0;
349-}
350- 
351-int64_t IDU::countRegisterDst(const DynamicInst& inst) const
352-{
353- int64_t dstCount = 0;
354- for (const auto& dst : inst.dst) {
355- if (analysis_.isVregName(dst))
356- ++dstCount;
357- }
358- return dstCount;
359-}
360- 
361-void IDU::consumeDispatchResources(
362- const DynamicInst& inst, const std::string& form, int64_t dstCount, DispatchResources& resources) const
363-{
364- resources.credits -= dstCount;
365- if (usesLsq(db_, inst.op, form)) {
366- --resources.lsqFree;
367- if (usesSharedShqCredit(db_, inst.op, form))
368- --resources.shqFree;
369- } else if (usesShqQueue(db_, inst.op, form)) {
370- --resources.shqQueueFree;
371- --resources.shqFree;
372- }
373-}
374- 
375-void IDU::recordDispatch(const DynamicInst& inst, int64_t cycle, const DispatchResources& resources)
376-{
377- window_.pop_front();
378- dispatchLog_.push_back(IDUDispatchRecord{
379- cycle,
380- inst.instId,
381- inst.op,
382- inst.dst,
383- inst.src,
384- inst.topBlockId,
385- resources.credits,
386- resources.shqQueueFree,
387- resources.lsqFree,
388- resources.shqFree,
389- });
390- updateLastDispatch(inst, cycle);
391- triggerNextVloops(inst, cycle);
392-}
393- 
394-std::vector<DynamicInst> IDU::dispatch(int64_t cycle, const IDUDispatchBudget& budget)
395-{
396- if (window_.empty())
397- return {};
398- 
399- const int64_t dispatchStartGate = std::max<int64_t>(0, vfStartupCost_ - iduDispatchStartAdvance_);
400- if (cycle < dispatchStartGate)
401- return {};
402- 
403- DispatchResources resources = makeDispatchResources(budget);
404- 
405- std::vector<DynamicInst> dispatched;
406- dispatched.reserve(static_cast<size_t>(std::max<int64_t>(0, resources.issueBudget)));
407- 
408- if (!hasInitialDispatchCredit(resources))
409- return {};
410- 
411- for (const auto& inst : window_) {
412- if (static_cast<int64_t>(dispatched.size()) >= resources.issueBudget)
413- break;
414- 
415- if (!isVloopDispatchOpen(inst, cycle, budget))
416- break;
417- 
418- const std::string& form = inst.form.empty() ? dtype_ : inst.form;
419- if (!hasQueueResource(inst, form, resources))
420- break;
421- 
422- const int64_t dstCount = countRegisterDst(inst);
423- if (resources.credits < dstCount)
424- break;
425- dispatched.push_back(inst);
426- consumeDispatchResources(inst, form, dstCount, resources);
427- }
428- 
429- for (const auto& inst : dispatched) {
430- recordDispatch(inst, cycle, resources);
431- }
432- 
433- return dispatched;
434-}
435- 
436-} // namespace vfsim
@@ -1,143 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_IDU_H
11-#define VFSIM_NATIVE_IDU_H
12- 
13-#include "pto/costmodel/a5/VfSim/IFU.h"
14- 
15-#include <deque>
16-#include <optional>
17-#include <string>
18-#include <unordered_map>
19-#include <vector>
20- 
21-namespace vfsim {
22- 
23-struct IDUDispatchBudget {
24- int64_t freePreg = 0;
25- int64_t freeShqQueue = 0;
26- int64_t freeLsq = 0;
27- int64_t freeShq = 0;
28- int64_t issueBudget = 0;
29- bool theoreticalLimitMode = false;
30- bool theoreticalLimitVloopOnly = false;
31-};
32- 
33-struct IDUDispatchRecord {
34- int64_t cycle = 0;
35- int64_t instId = 0;
36- std::string op;
37- std::vector<std::string> dst;
38- std::vector<std::string> src;
39- int64_t topBlockId = 0;
40- int64_t vreg = 0;
41- int64_t shqQueue = 0;
42- int64_t lsq = 0;
43- int64_t shq = 0;
44-};
45- 
46-struct VloopTraceRecord {
47- int64_t topBlockId = 0;
48- std::string loopId;
49- std::vector<int64_t> iter;
50- int64_t startCycle = 0;
51-};
52- 
53-class IDU {
54-public:
55- IDU(const UarchConfig& uarch, const ParamDB& db, ProgramAnalysis::ParamMap params = {},
56- std::vector<int64_t> loopBounds = {}, int64_t totalTopBlocks = 1,
57- std::unordered_map<int, std::vector<int64_t>> topBlockLoopBounds = {}, std::string dtype = "fp32",
58- std::unordered_map<std::string, ValueInfo> values = {});
59- 
60- bool empty() const noexcept { return window_.empty(); }
61- bool canAccept() const;
62- void accept(const DynamicInst& inst);
63- 
64- std::vector<DynamicInst> dispatch(int64_t cycle, const IDUDispatchBudget& budget);
65- 
66- const ParamDB& db() const noexcept { return db_; }
67- const std::vector<IDUDispatchRecord>& dispatchLog() const noexcept { return dispatchLog_; }
68- const std::vector<VloopTraceRecord>& vloopTrace() const noexcept { return vloopTrace_; }
69- 
70-private:
71- struct DispatchResources {
72- int64_t credits = 0;
73- int64_t shqQueueFree = 0;
74- int64_t lsqFree = 0;
75- int64_t shqFree = 0;
76- int64_t issueBudget = 0;
77- };
78- 
79- const ParamDB& db_;
80- std::string dtype_;
81- int64_t windowWidth_ = 0;
82- int64_t issueWidth_ = 0;
83- bool theoreticalLimitMode_ = false;
84- bool theoreticalLimitVloopOnly_ = false;
85- int64_t vfStartupCost_ = 0;
86- int64_t iduDispatchStartAdvance_ = 0;
87- int64_t vloopToDispatchDelay_ = 4;
88- int64_t initialTopBlockVloopStartCycle_ = 19;
89- int64_t nestedVloopInitialStartGap_ = 1;
90- int64_t loop1MinFeedbackGap_ = 7;
91- int64_t innermostIterDispatchStride_ = 1;
92- bool globalShqPregGate_ = false;
93- 
94- std::deque<DynamicInst> window_;
95- ProgramAnalysis analysis_;
96- std::vector<int64_t> loopBounds_;
97- int64_t totalTopBlocks_ = 1;
98- std::unordered_map<int, std::vector<int64_t>> topBlockLoopBounds_;
99- 
100- std::unordered_map<int64_t, int64_t> topBlockVloopStart_;
101- std::unordered_map<int64_t, int64_t> topBlockBodyOpenTime_;
102- std::unordered_map<std::string, int64_t> vloopStart_;
103- std::unordered_map<std::string, int64_t> bodyOpenTime_;
104- std::unordered_map<std::string, int64_t> lastDispatchTime_;
105- std::unordered_map<std::string, int64_t> blockBaseCycle_;
106- std::vector<VloopTraceRecord> vloopTrace_;
107- std::vector<IDUDispatchRecord> dispatchLog_;
108- 
109- void initVloopStarts();
110- void setTopBlockVloop(int64_t topBlockId, int64_t startCycle);
111- void initTopBlockNestedStarts(int64_t topBlockId, int64_t topVloopStart);
112- const std::vector<int64_t>& loopBoundsForTopBlock(int64_t topBlockId) const;
113- bool hasBlockEndLevel(const DynamicInst& inst, int64_t level) const;
114- void triggerNextTopBlock(const DynamicInst& inst, int64_t cycle);
115- int64_t lastDispatchOrCycle(const std::string& key, int64_t cycle) const;
116- void openLoopBody(const std::string& key, int64_t startCycle);
117- std::optional<int64_t> nextLoop1Start(
118- const DynamicInst& inst, const std::vector<int64_t>& bounds, int64_t cycle) const;
119- void triggerDepth2Vloops(const DynamicInst& inst, const std::vector<int64_t>& bounds, int64_t cycle);
120- void triggerDepth3InnerVloops(const DynamicInst& inst, const std::vector<int64_t>& bounds, int64_t cycle);
121- void triggerDepth3OuterVloops(const DynamicInst& inst, const std::vector<int64_t>& bounds, int64_t cycle);
122- 
123- std::string makeKey(int64_t topBlockId, const std::string& loopId, const std::vector<int64_t>& iters) const;
124- std::optional<std::string> normalizeBlockKey(
125- const std::pair<std::string, std::vector<int64_t>>& raw, int64_t topBlockId) const;
126- std::optional<std::string> currentInnerBlockKey(const DynamicInst& inst) const;
127- 
128- void updateLastDispatch(const DynamicInst& inst, int64_t cycle);
129- void triggerNextVloops(const DynamicInst& inst, int64_t cycle);
130- DispatchResources makeDispatchResources(const IDUDispatchBudget& budget) const;
131- bool hasInitialDispatchCredit(const DispatchResources& resources) const;
132- bool isVloopDispatchOpen(const DynamicInst& inst, int64_t cycle, const IDUDispatchBudget& budget);
133- bool hasQueueResource(const DynamicInst& inst, const std::string& form, const DispatchResources& resources) const;
134- int64_t countRegisterDst(const DynamicInst& inst) const;
135- void consumeDispatchResources(
136- const DynamicInst& inst, const std::string& form, int64_t dstCount, DispatchResources& resources) const;
137- void recordDispatch(const DynamicInst& inst, int64_t cycle, const DispatchResources& resources);
138- bool isLastInstOfTopBlock(const DynamicInst& inst) const;
139-};
140- 
141-} // namespace vfsim
142- 
143-#endif // VFSIM_NATIVE_IDU_H
@@ -1,512 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#include "pto/costmodel/a5/VfSim/IFU.h"
11- 
12-#include <algorithm>
13-#include <stdexcept>
14-#include <utility>
15- 
16-namespace vfsim {
17-namespace {
18- 
19-int64_t resolveInt(
20- const std::string& text, const ProgramAnalysis::ParamMap& params, int64_t defaultValue, int64_t minValue)
21-{
22- if (text.empty())
23- return defaultValue;
24- bool digits = true;
25- size_t pos = 0;
26- if (text[0] == '-') {
27- pos = 1;
28- digits = text.size() > 1;
29- }
30- for (; digits && pos < text.size(); ++pos) {
31- if (!std::isdigit(static_cast<unsigned char>(text[pos])))
32- digits = false;
33- }
34- if (digits) {
35- try {
36- return std::max<int64_t>(minValue, std::stoll(text));
37- } catch (...) {
38- return defaultValue;
39- }
40- }
41- auto it = params.find(text);
42- if (it != params.end())
43- return std::max<int64_t>(minValue, it->second);
44- return defaultValue;
45-}
46- 
47-} // namespace
48- 
49-IFU::IFU(
50- const std::vector<LinearProgramNode>& linearNodes, ProgramAnalysis::ParamMap params, const ParamDB* db,
51- std::unordered_map<int, std::vector<int64_t>> topBlockLoopBounds, int64_t totalTopBlocks, std::string dtype)
52- : nodes_(linearNodes), analysis_(std::move(params)), dtype_(std::move(dtype))
53-{
54- db_ = db;
55- buildIndices();
56- if (!topBlockLoopBounds.empty())
57- topBlockLoopBounds_ = std::move(topBlockLoopBounds);
58- else
59- topBlockLoopBounds_ = analysis_.inferTopBlockLoopBounds({});
60- if (totalTopBlocks > 0)
61- totalTopBlocks_ = totalTopBlocks;
62-}
63- 
64-bool IFU::isInst(const LinearProgramNode& node) { return node.type == "inst"; }
65-bool IFU::isLoopBegin(const LinearProgramNode& node) { return node.type == "loop_begin"; }
66-bool IFU::isLoopEnd(const LinearProgramNode& node) { return node.type == "loop_end"; }
67- 
68-bool IFU::containsAnyLoop(const std::vector<LinearProgramNode>& nodes)
69-{
70- for (const auto& node : nodes) {
71- if (node.type == "loop_begin")
72- return true;
73- }
74- return false;
75-}
76- 
77-void IFU::buildIndices()
78-{
79- const std::vector<int64_t> begins = collectLoopBegins();
80- markInnermostLoops(begins);
81- assignTopBlockIds(begins);
82- cacheLoopBodies(begins);
83- cacheTopBlockLastInsts();
84-}
85- 
86-std::vector<int64_t> IFU::collectLoopBegins()
87-{
88- std::vector<int64_t> stack;
89- for (int64_t i = 0; i < static_cast<int64_t>(nodes_.size()); ++i) {
90- const auto& node = nodes_[static_cast<size_t>(i)];
91- if (isLoopBegin(node)) {
92- stack.push_back(i);
93- beginLoopId_[i] = static_cast<int64_t>(beginLoopId_.size());
94- } else if (isLoopEnd(node)) {
95- if (stack.empty())
96- throw std::runtime_error("Unmatched loop_end in linear program");
97- const int64_t begin = stack.back();
98- stack.pop_back();
99- beginToEnd_[begin] = i;
100- }
@@ -1,145 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_IFU_H
11-#define VFSIM_NATIVE_IFU_H
12- 
13-#include "pto/costmodel/a5/VfSim/ParamDB.h"
14-#include "pto/costmodel/a5/VfSim/ProgramFlatten.h"
15- 
16-#include <deque>
17-#include <optional>
18-#include <string>
19-#include <utility>
20-#include <vector>
21- 
22-namespace vfsim {
23- 
24-struct DynamicInst {
25- int64_t instId = 0;
26- std::string type = "inst";
27- std::string op;
28- std::string form;
29- std::vector<std::string> src;
30- std::vector<std::string> dst;
31- 
32- std::vector<int64_t> loopStack;
33- std::vector<int64_t> iterStack;
34- int64_t loopDepth = 0;
35- bool inLoop = false;
36- 
37- int64_t unrollFactor = 1;
38- int64_t lane = -1;
39- int64_t unrollGroup = 0;
40- int64_t origIterBase = 0;
41- int64_t topBlockId = 0;
42- bool isLastInTopBlock = false;
43- std::vector<std::pair<std::string, std::vector<int64_t>>> blockKeyByLevel;
44- std::vector<int64_t> blockEndLevels;
45-};
46- 
47-class IFU {
48-public:
49- IFU(const std::vector<LinearProgramNode>& linearNodes, ProgramAnalysis::ParamMap params = {},
50- const ParamDB* db = nullptr, std::unordered_map<int, std::vector<int64_t>> topBlockLoopBounds = {},
51- int64_t totalTopBlocks = 0, std::string dtype = "fp32");
52- 
53- bool done() const;
54- std::optional<DynamicInst> nextInst();
55- std::vector<DynamicInst> take(int64_t n);
56- 
57- int totalTopBlocks() const noexcept { return totalTopBlocks_; }
58- const std::unordered_map<int, std::vector<int64_t>>& topBlockLoopBounds() const noexcept
59- {
60- return topBlockLoopBounds_;
61- }
62- const std::vector<std::pair<int64_t, std::vector<int64_t>>>& vloopTrace() const noexcept { return vloopTrace_; }
63- 
64-private:
65- struct LoopFrame {
66- int64_t beginIdx = 0;
67- int64_t endIdx = 0;
68- int64_t loopId = 0;
69- int64_t itersTotal = 0;
70- int64_t iterNow = 0;
71- bool isInnermost = false;
72- int64_t unroll = 1;
73- int64_t topBlockId = 0;
74- };
75- 
76- std::vector<LinearProgramNode> nodes_;
77- ProgramAnalysis analysis_;
78- const ParamDB* db_ = nullptr;
79- std::string dtype_;
80- 
81- std::unordered_map<int64_t, int64_t> beginToEnd_;
82- std::unordered_map<int64_t, int64_t> beginLoopId_;
83- std::unordered_map<int64_t, bool> isInnermostBegin_;
84- std::unordered_map<int64_t, int64_t> beginTopBlockId_;
85- std::unordered_map<int64_t, std::vector<LinearProgramNode>> loopBodyCache_;
86- std::unordered_map<int64_t, std::optional<int64_t>> loopLastInstIdx_;
87- std::unordered_map<int64_t, std::optional<int64_t>> topBlockLastInstIdx_;
88- int64_t totalTopBlocks_ = 0;
89- 
90- int64_t pc_ = 0;
91- int64_t instId_ = 0;
92- int64_t unrollGroup_ = 0;
93- std::deque<DynamicInst> pending_;
94- std::vector<LoopFrame> frames_;
95- std::vector<std::pair<int64_t, std::vector<int64_t>>> vloopTrace_;
96- std::unordered_map<int, std::vector<int64_t>> topBlockLoopBounds_;
97- 
98- void buildIndices();
99- std::vector<int64_t> collectLoopBegins();
100- void markInnermostLoops(const std::vector<int64_t>& begins);
101- void assignTopBlockIds(const std::vector<int64_t>& begins);
102- std::optional<int64_t> findLastInstIdx(int64_t begin, int64_t end) const;
103- void cacheLoopBodies(const std::vector<int64_t>& begins);
104- void cacheTopBlockLastInsts();
105- static bool containsAnyLoop(const std::vector<LinearProgramNode>& nodes);
106- static bool isInst(const LinearProgramNode& node);
107- static bool isLoopBegin(const LinearProgramNode& node);
108- static bool isLoopEnd(const LinearProgramNode& node);
109- 
110- std::pair<std::vector<int64_t>, std::vector<int64_t>> snapshot() const;
111- int64_t currentTopBlockId() const;
112- std::pair<std::string, std::vector<int64_t>> normalizeBlockKey(
113- const std::pair<std::string, std::vector<int64_t>>& raw, int64_t topBlockId) const;
114- std::pair<std::string, std::vector<int64_t>> makeKey(
115- int64_t topBlockId, const std::string& loopId, std::vector<int64_t> it) const;
116- std::pair<std::vector<int64_t>, std::vector<int64_t>> currentBlockKeyPair(const DynamicInst& inst) const;
117- 
118- std::vector<std::pair<std::string, std::vector<int64_t>>> buildBlockKeyByLevel(
119- const std::vector<int64_t>& loopStack, const std::vector<int64_t>& iterStack) const;
120- std::vector<int64_t> calcBlockEndLevelsNormal() const;
121- bool areFinalLoopIterations(
122- int64_t firstLevel, int64_t deepest, const LoopFrame* unrolledFrame, bool isLastSuperIter) const;
123- bool isLastInTopBlockNormal() const;
124- DynamicInst emitNormalInst(const LinearProgramNode& node);
125- DynamicInst emitUnrolledInst(
126- const LinearProgramNode& node, const LoopFrame& frame, const std::vector<int64_t>& loopStack,
127- const std::vector<int64_t>& iterStack, int64_t superIter, int64_t lane);
128- std::vector<int64_t> calcBlockEndLevelsUnrolled(
129- const std::vector<int64_t>& loopStack, const LoopFrame& frame, bool isLastSuperIter) const;
130- bool isLastUnrolledTopBlock(const LoopFrame& frame) const;
131- void markLastPendingUnrolled(
132- std::vector<DynamicInst>& pending, const std::vector<int64_t>& loopStack, const LoopFrame& frame,
133- bool isLastSuperIter) const;
134- void buildPendingUnrolled(LoopFrame& frame);
135- std::optional<DynamicInst> popPending();
136- void enterLoop(const LinearProgramNode& node);
137- std::optional<DynamicInst> handleLoopEnd();
138- 
139- void updateLastDispatch(const DynamicInst& inst, int64_t cycle);
140- void triggerNextVloops(const DynamicInst& inst, int64_t cycle);
141-};
142- 
143-} // namespace vfsim
144- 
145-#endif // VFSIM_NATIVE_IFU_H
@@ -1,95 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#include "pto/costmodel/a5/VfSim/ISATraits.h"
11- 
12-#include <cctype>
13-#include <algorithm>
14- 
15-namespace vfsim {
16-namespace {
17- 
18-std::string canonicalOp(std::string op)
19-{
20- std::transform(
21- op.begin(), op.end(), op.begin(), [](unsigned char c) { return static_cast<char>(std::toupper(c)); });
22- return op;
23-}
24- 
25-OpClass opClassFromString(const std::string& text)
26-{
27- const std::string canon = canonicalOp(text);
28- if (canon == "LOAD")
29- return OpClass::Load;
30- if (canon == "STORE")
31- return OpClass::Store;
32- if (canon == "COMPUTE")
33- return OpClass::Compute;
34- return OpClass::Unknown;
35-}
36- 
37-OpClass opClassFromNameFallback(const std::string& op)
38-{
39- const std::string canon = canonicalOp(op);
40- if (canon == "VLDS" || canon == "VLD")
41- return OpClass::Load;
42- if (canon == "VSTS" || canon == "VST" || canon == "VSTUS" || canon == "VSTAS")
43- return OpClass::Store;
44- return OpClass::Compute;
45-}
46- 
47-} // namespace
48- 
49-OpClass getOpClass(const ParamDB& db, const std::string& op, const std::string& dtype)
50-{
51- const std::string canonOp = canonicalOp(op);
52- if (db.hasInst(canonOp, dtype)) {
53- const InstConfig& cfg = db.inst(canonOp, dtype);
54- const OpClass opClass = opClassFromString(cfg.opClass);
55- if (opClass != OpClass::Unknown)
56- return opClass;
57- if (!cfg.exu.empty() || !cfg.dispatchExu.empty())
58- return OpClass::Compute;
59- }
60- return opClassFromNameFallback(canonOp);
61-}
62- 
63-bool isLoadOp(const ParamDB& db, const std::string& op, const std::string& dtype)
64-{
65- return getOpClass(db, op, dtype) == OpClass::Load;
66-}
67- 
68-bool isStoreOp(const ParamDB& db, const std::string& op, const std::string& dtype)
69-{
70- return getOpClass(db, op, dtype) == OpClass::Store;
71-}
72- 
73-bool isComputeOp(const ParamDB& db, const std::string& op, const std::string& dtype)
74-{
75- return getOpClass(db, op, dtype) == OpClass::Compute;
76-}
77- 
78-bool usesLsq(const ParamDB& db, const std::string& op, const std::string& dtype)
79-{
80- const OpClass cls = getOpClass(db, op, dtype);
81- return cls == OpClass::Load || cls == OpClass::Store;
82-}
83- 
84-bool usesShqQueue(const ParamDB& db, const std::string& op, const std::string& dtype)
85-{
86- return isComputeOp(db, op, dtype);
87-}
88- 
89-bool usesSharedShqCredit(const ParamDB& db, const std::string& op, const std::string& dtype)
90-{
91- const OpClass cls = getOpClass(db, op, dtype);
92- return cls == OpClass::Compute || cls == OpClass::Store;
93-}
94- 
95-} // namespace vfsim
@@ -1,36 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_ISA_TRAITS_H
11-#define VFSIM_NATIVE_ISA_TRAITS_H
12- 
13-#include "pto/costmodel/a5/VfSim/ParamDB.h"
14- 
15-#include <string>
16- 
17-namespace vfsim {
18- 
19-enum class OpClass {
20- Load,
21- Store,
22- Compute,
23- Unknown,
24-};
25- 
26-OpClass getOpClass(const ParamDB& db, const std::string& op, const std::string& dtype = "fp32");
27-bool isLoadOp(const ParamDB& db, const std::string& op, const std::string& dtype = "fp32");
28-bool isStoreOp(const ParamDB& db, const std::string& op, const std::string& dtype = "fp32");
29-bool isComputeOp(const ParamDB& db, const std::string& op, const std::string& dtype = "fp32");
30-bool usesLsq(const ParamDB& db, const std::string& op, const std::string& dtype = "fp32");
31-bool usesShqQueue(const ParamDB& db, const std::string& op, const std::string& dtype = "fp32");
32-bool usesSharedShqCredit(const ParamDB& db, const std::string& op, const std::string& dtype = "fp32");
33- 
34-} // namespace vfsim
35- 
36-#endif // VFSIM_NATIVE_ISA_TRAITS_H
@@ -1,84 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_JSON_DUMP_UTILS_H
11-#define VFSIM_NATIVE_JSON_DUMP_UTILS_H
12- 
13-#include <optional>
14-#include <sstream>
15-#include <string>
16-#include <vector>
17- 
18-namespace vfsim {
19- 
20-inline std::string jsonEscape(const std::string& text)
21-{
22- std::string out;
23- out.reserve(text.size() + 8);
24- for (char c : text) {
25- switch (c) {
26- case '\\':
27- out += "\\\\";
28- break;
29- case '"':
30- out += "\\\"";
31- break;
32- case '\n':
33- out += "\\n";
34- break;
35- case '\r':
36- out += "\\r";
37- break;
38- case '\t':
39- out += "\\t";
40- break;
41- default:
42- out.push_back(c);
43- break;
44- }
45- }
46- return out;
47-}
48- 
49-template <typename T>
50-inline void appendJsonValue(std::ostringstream& oss, const T& value)
51-{
52- oss << value;
53-}
54- 
55-inline void appendJsonValue(std::ostringstream& oss, const std::string& value)
56-{
57- oss << '"' << jsonEscape(value) << '"';
58-}
59- 
60-inline void appendJsonValue(std::ostringstream& oss, const std::optional<std::string>& value)
61-{
62- if (value.has_value())
63- appendJsonValue(oss, *value);
64- else
65- oss << "null";
66-}
67- 
68-template <typename T>
69-inline std::string joinJsonArray(const std::vector<T>& values)
70-{
71- std::ostringstream oss;
72- oss << "[";
73- for (size_t i = 0; i < values.size(); ++i) {
74- if (i)
75- oss << ", ";
76- appendJsonValue(oss, values[i]);
77- }
78- oss << "]";
79- return oss.str();
80-}
81- 
82-} // namespace vfsim
83- 
84-#endif // VFSIM_NATIVE_JSON_DUMP_UTILS_H
@@ -1,284 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_OOO_H
11-#define VFSIM_NATIVE_OOO_H
12- 
13-#include "pto/costmodel/a5/VfSim/IDU.h"
14-#include "pto/costmodel/a5/VfSim/ValueStorage.h"
15- 
16-#include <deque>
17-#include <optional>
18-#include <string>
19-#include <unordered_map>
20-#include <unordered_set>
21-#include <vector>
22- 
23-namespace vfsim {
24- 
25-struct Uop {
26- int64_t instId = 0;
27- std::string op;
28- std::string form;
29- std::vector<std::string> src;
30- std::vector<std::string> dst;
31- std::vector<std::optional<std::string>> pregSrc;
32- std::vector<std::optional<int64_t>> pregSrcGen;
33- std::vector<std::string> pregDst;
34- std::vector<std::optional<std::string>> pregOld;
35- 
36- std::string state = "blocked";
37- int64_t readyCycle = 0;
38- std::optional<int64_t> startCycle;
39- std::optional<int64_t> doneCycle;
40- 
41- std::optional<std::string> producerOpForStore;
42- std::optional<std::string> producerFormForStore;
43- std::optional<int64_t> producerStartForStore;
44- std::vector<Uop*> memDepUops;
45- int64_t topBlockId = 0;
46- std::vector<int64_t> iterStack;
47- bool isLastInTopBlock = false;
48- int exuPort = -1;
49- int64_t shqReadyCycle = 0;
50- int64_t lsqReadyCycle = 0;
51- bool isShqTracked = false;
52- int64_t exqRecvCycle = 0;
53- int64_t exqPredIssue = 0;
54-};
55- 
56-struct SrcReleaseEvent {
57- int64_t instId = 0;
58- std::string preg;
59- int64_t gen = 0;
60-};
61- 
62-struct ProducerInfo {
63- std::string op;
64- std::string form;
65- int64_t startCycle = 0;
66- std::string kind;
67-};
68- 
69-struct HistoryRecord {
70- int64_t cy = 0;
71- std::string event;
72- int64_t id = 0;
73- std::string op;
74- std::string state;
75- int64_t ready = 0;
76- std::optional<int64_t> start;
77- std::optional<int64_t> done;
78- std::vector<std::string> src;
79- std::vector<std::string> dst;
80- std::vector<std::optional<std::string>> pregSrc;
81- std::vector<std::string> pregDst;
82- std::vector<std::optional<std::string>> pregOld;
83- std::optional<std::string> producerOpForStore;
84- std::optional<int64_t> producerStartForStore;
85-};
86- 
87-struct SimpleLogRecord {
88- int64_t cy = 0;
89- int64_t instId = 0;
90- std::string op;
91- std::vector<std::string> dst;
92- std::vector<std::string> src;
93-};
94- 
95-class OoOCore {
96-public:
97- OoOCore(
98- const UarchConfig& uarch, const ParamDB& db, std::string dtype = "fp32",
99- const std::unordered_map<std::string, ValueInfo>& values = {});
100- virtual ~OoOCore() = default;
101- 
102- int getFreePreg() const;
103- int getFreeShqQueue() const;
104- int getFreeLsq() const;
105- int getFreeShq() const;
106- int getRobSize() const noexcept { return static_cast<int>(rob_.size()); }
107- int getLsqSize() const noexcept { return static_cast<int>(lsq_.size()); }
108- int getShqSize() const noexcept { return static_cast<int>(shq_.size()); }
109- virtual std::unordered_map<std::string, int> updateIduVisibility(int64_t cycle);
110- 
111- virtual void accept(const DynamicInst& inst) = 0;
112- virtual void step() = 0;
113- virtual int64_t vfEndCycle() const;
114- virtual void dumpHistory(const std::string& path) const;
115- virtual void dumpSimpleLogs(const std::string& startPath, const std::string& donePath) const;
116- 
117-protected:
118- const ParamDB& db_;
119- std::string dtype_;
120- ValueStorageLookup valueStorage_;
121- bool theoreticalLimitMode_ = false;
122- bool enableIsuQueueModel_ = false;
123- int loadPorts_ = 2;
124- int issuePorts_ = 2;
125- int storePorts_ = 1;
126- int shqDepth_ = 58;
127- int lsqDepth_ = 24;
128- int pregNum_ = 68;
129- int vfStartupCost_ = 0;
130- int vfDrainCost_ = 0;
131- int64_t cycle_ = 0;
132- int64_t lastDoneCycle_ = 0;
133- 
134- std::deque<std::string> freelist_;
135- std::unordered_map<std::string, std::string> rat_;
136- int64_t nextDynamicPregId_ = 0;
137- 
138- std::deque<Uop> shq_;
139- std::deque<Uop> lsq_;
140- std::deque<Uop> rob_;
141- 
142- std::unordered_map<std::string, ProducerInfo> pregProducer_;
143- std::vector<int64_t> lastIssueCycleALU_;
144- std::vector<int64_t> lastIssueCycleSFU_;
145- std::vector<std::string> lastOpALU_;
146- std::vector<std::string> lastFormALU_;
147- std::vector<std::string> lastOpSFU_;
148- std::vector<std::string> lastFormSFU_;
149- std::vector<int64_t> lastIssueCycleExu_;
150- std::vector<std::string> lastOpExu_;
151- std::vector<std::string> lastFormExu_;
152- std::vector<int> exqInflight_;
153- 
154- int loadDoneLatency_ = 9;
155- int oooToShqDelay_ = 1;
156- int oooToLsqDelay_ = 1;
157- int exqRecvDelay_ = 1;
158- bool memBarStrong_ = false;
159- bool enforceSameCycleSrcHazard_ = true;
160- bool enableExqGreedyBalance_ = false;
161- bool enableShqCreditModel_ = false;
162- bool enableCreditVisibilityDelay_ = false;
163- bool enableCrossFuIi_ = false;
164- bool exqCapacityCountsInflight_ = false;
165- int exqDepth_ = 26;
166- int shqToExqPortPerCycle_ = 1;
167- int exqIssueInflightCapPerPort_ = 0;
168- int computeInflightCap_ = 0;
169- int shqReleaseDelay_ = 1;
170- int iduVisiblePregDelay_ = 0;
171- int iduVisibleShqDelay_ = 0;
172- int visiblePregFree_ = 0;
173- int visibleShqUsed_ = 0;
174- int shqUsed_ = 0;
175- std::unordered_map<int64_t, int> visiblePregFreeEvents_;
176- std::unordered_map<int64_t, int> visibleShqReleaseEvents_;
177- std::unordered_map<int64_t, int> shqReleaseEvents_;
178- std::unordered_map<int64_t, int> blockOutstandingStores_;
179- std::unordered_map<int64_t, bool> blockLastInstDone_;
180- std::unordered_map<int64_t, int64_t> blockReleaseCycle_;
181- int iduMailboxPregReleaseDelta_ = 0;
182- int iduMailboxShqReleaseDelta_ = 0;
183- int consumerReleaseStartOffset_ = 0;
184- std::unordered_map<std::string, int> pregConsumerCount_;
185- std::unordered_set<std::string> pregPending_;
186- std::unordered_map<std::string, int64_t> pregReleaseEligibleCycle_;
187- std::unordered_map<std::string, int64_t> pregGeneration_;
188- std::unordered_map<int64_t, std::vector<SrcReleaseEvent>> srcReleaseEvents_;
189- std::unordered_map<int64_t, int> srcReleaseExpected_;
190- std::unordered_map<int64_t, int> srcReleaseSeen_;
191- std::unordered_set<int64_t> srcReleaseScheduledInstIds_;
192- 
193- std::vector<HistoryRecord> history_;
194- std::vector<SimpleLogRecord> startLogs_;
195- std::vector<SimpleLogRecord> doneLogs_;
196- 
197- virtual std::string classifyOpClass(const std::string& op, const std::string& form) const;
198- bool isRegisterValue(const std::string& name) const;
199- bool isUBValue(const std::string& name) const;
200- int64_t computeReadyTimeForSrc(
201- const ProducerInfo& producerInfo, const std::string& consumerOp, const std::string& consumerForm) const;
202- int64_t computeLoadReadyCycle(const Uop& u) const;
203- std::tuple<int64_t, std::optional<std::string>, std::optional<std::string>, std::optional<int64_t>>
204- computeStoreReadyCycle(const Uop& u) const;
205- int64_t dataStoreCost(const std::string& producerOp, const std::string& producerForm) const;
206- std::string getFuType(const std::string& op, const std::string& form) const;
207- std::vector<int> eligibleExuPorts(const std::string& op, const std::string& form) const;
208- int64_t getIi(
209- const std::string* prevOp, const std::string* prevForm, const std::string& curOp,
210- const std::string& curForm) const;
211- void log(const std::string& event, const Uop& u);
212- void logStartSimple(const Uop& u);
213- void logDoneSimple(const Uop& u);
214- Uop* findRobUop(int64_t instId);
215- bool isCurrentMapping(const std::string& preg) const;
216- void scheduleSrcReleaseFromStart(const Uop& u);
217- void runSrcReleaseEvents(int64_t cycle);
218- bool tryFreePreg(const std::string& preg, int64_t cycle);
219- void tryFreeEligiblePregs(int64_t cycle);
220- int exqOccupancy(int port) const;
221- int totalComputeInflight() const;
222- int64_t predictExqIssueCycle(
223- int port, const std::string& fuType, const std::string& op, const std::string& form, int64_t recvCycle) const;
224- void scheduleShqRelease(int64_t cycle, int count = 1);
225- void runShqReleaseEvents(int64_t cycle);
226- 
227- virtual void freeOldPregs(const Uop& u) = 0;
228-};
229- 
230-class OoOCoreMainline final : public OoOCore {
231-public:
232- OoOCoreMainline(
233- const UarchConfig& uarch, const ParamDB& db, std::string dtype = "fp32",
234- const std::unordered_map<std::string, ValueInfo>& values = {});
235- 
236- void accept(const DynamicInst& inst) override;
237- void step() override;
238- 
239-private:
240- struct ExqChoice {
241- int port = -1;
242- int64_t pred = 0;
243- int occ = 0;
244- };
245- 
246- std::vector<int> exqInflightPerPort_;
247- std::vector<std::unordered_map<std::string, std::deque<Uop>>> exqWait_;
248- 
249- void freeOldPregs(const Uop& u) override;
250- Uop makeAcceptedUop(const DynamicInst& inst) const;
251- void capturePregSources(Uop& u) const;
252- void addPregConsumers(const Uop& u);
253- int allocatePregDsts(Uop& u);
254- void trackSharedShqCredit(Uop& u);
255- void enqueueAcceptedUop(Uop& u);
256- void releaseOldMappings(const Uop& u);
257- void completeRunningUops(int64_t cycle);
258- void retireDoneUops();
259- int64_t computeShqReadyCycle(const Uop& u) const;
260- void updateLsqReadiness(int64_t cycle);
261- void updateShqReadiness(int64_t cycle);
262- void mirrorStartedUopToRob(const Uop& u);
263- void markProducerReady(const Uop& u, const std::string& kind);
264- bool hasSameCycleSrcHazard(const Uop& u, const std::unordered_set<std::string>& issuedSrcs) const;
265- void rememberIssuedSrcs(const Uop& u, std::unordered_set<std::string>& issuedSrcs) const;
266- void issueReadyLoads(int64_t cycle);
267- int chooseDirectIssuePort(const Uop& u, const std::vector<bool>& exuUsedThisCycle) const;
268- void recordComputeIssue(Uop& u, int64_t cycle, int port, const std::string& fuType);
269- void issueReadyComputeDirect(
270- int64_t cycle, std::vector<bool>& exuUsedThisCycle, std::unordered_set<std::string>& issuedSrcsThisCycle);
271- void enqueueReadyComputeToExq(int64_t cycle, std::unordered_set<std::string>& issuedSrcsThisCycle);
272- ExqChoice chooseExqEnqueuePort(
273- const Uop& u, const std::string& fuType, const std::vector<int>& shqToExqCnt, int64_t cycle) const;
274- void moveUopToExqWait(Uop& u, int64_t cycle, const ExqChoice& choice, const std::string& fuType);
275- Uop* selectExqIssueCandidate(int port, int64_t cycle, std::string& fuType);
276- void issueExqWaitQueues(int64_t cycle, std::vector<bool>& exuUsedThisCycle);
277- void issueReadyComputeViaIsu(
278- int64_t cycle, std::vector<bool>& exuUsedThisCycle, std::unordered_set<std::string>& issuedSrcsThisCycle);
279- void issueReadyStores(int64_t cycle);
280-};
281- 
282-} // namespace vfsim
283- 
284-#endif // VFSIM_NATIVE_OOO_H
@@ -1,253 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#include "pto/costmodel/a5/VfSim/ParamDB.h"
11- 
12-#include "pto/costmodel/a5/VfSim/VfSimParamsGenerated.h"
13- 
14-#include <algorithm>
15-#include <array>
16-#include <stdexcept>
17-#include <string>
18-#include <string_view>
19-#include <utility>
20- 
21-namespace vfsim {
22-namespace {
23- 
24-struct IntUarchParam {
25- std::string_view key;
26- int64_t UarchConfig::*member;
27-};
28- 
29-struct BoolUarchParam {
30- std::string_view key;
31- bool UarchConfig::*member;
32-};
33- 
34-inline constexpr std::array<IntUarchParam, 27> kIntUarchParams = {{
35- {"issue_ports", &UarchConfig::issuePorts},
36- {"load_ports", &UarchConfig::loadPorts},
37- {"store_ports", &UarchConfig::storePorts},
38- {"IDU_window_width", &UarchConfig::iduWindowWidth},
39- {"IDU_issue_width", &UarchConfig::iduIssueWidth},
40- {"LDQ_width", &UarchConfig::ldqWidth},
41- {"vreg_num", &UarchConfig::vregNum},
42- {"shq_depth", &UarchConfig::shqDepth},
43- {"exq_depth", &UarchConfig::exqDepth},
44- {"shq_release_delay", &UarchConfig::shqReleaseDelay},
45- {"idu_visible_preg_delay", &UarchConfig::iduVisiblePregDelay},
46- {"idu_visible_shq_delay", &UarchConfig::iduVisibleShqDelay},
47- {"idu_to_ooo_delay", &UarchConfig::iduToOooDelay},
48- {"vloop_to_dispatch_delay", &UarchConfig::vloopToDispatchDelay},
49- {"idu_dispatch_start_advance", &UarchConfig::iduDispatchStartAdvance},
50- {"initial_top_block_vloop_start_cycle", &UarchConfig::initialTopBlockVloopStartCycle},
51- {"nested_vloop_initial_start_gap", &UarchConfig::nestedVloopInitialStartGap},
52- {"loop1_min_feedback_gap", &UarchConfig::loop1MinFeedbackGap},
53- {"innermost_iter_dispatch_stride", &UarchConfig::innermostIterDispatchStride},
54- {"consumer_release_start_offset", &UarchConfig::consumerReleaseStartOffset},
55- {"load_done_latency", &UarchConfig::loadDoneLatency},
56- {"ooo_to_shq_delay", &UarchConfig::oooToShqDelay},
57- {"ooo_to_lsq_delay", &UarchConfig::oooToLsqDelay},
58- {"exq_recv_delay", &UarchConfig::exqRecvDelay},
59- {"shq_to_exq_port_per_cycle", &UarchConfig::shqToExqPortPerCycle},
60- {"compute_inflight_cap", &UarchConfig::computeInflightCap},
61- {"exq_issue_inflight_cap_per_port", &UarchConfig::exqIssueInflightCapPerPort},
62-}};
63- 
64-inline constexpr std::array<BoolUarchParam, 9> kBoolUarchParams = {{
65- {"enable_isu_queue_model", &UarchConfig::enableIsuQueueModel},
66- {"admit_blocked_to_exq", &UarchConfig::admitBlockedToExq},
67- {"enable_shq_credit_model", &UarchConfig::enableShqCreditModel},
68- {"enable_credit_visibility_delay", &UarchConfig::enableCreditVisibilityDelay},
69- {"global_shq_preg_gate", &UarchConfig::globalShqPregGate},
70- {"use_explicit_idu_credit_bank", &UarchConfig::useExplicitIduCreditBank},
71- {"exq_capacity_counts_inflight", &UarchConfig::exqCapacityCountsInflight},
72- {"enforce_same_cycle_src_hazard", &UarchConfig::enforceSameCycleSrcHazard},
73- {"enable_cross_fu_ii", &UarchConfig::enableCrossFuIi},
74-}};
75- 
76-std::string toString(std::string_view value) { return std::string(value.data(), value.size()); }
77- 
78-int64_t parseInt(std::string_view value) { return std::stoll(toString(value)); }
79- 
80-bool parseBool(std::string_view value) { return value == "true" || value == "1"; }
81- 
82-std::pair<std::string, std::string> splitQualifiedOp(const std::string& name)
83-{
84- const std::size_t dot = name.rfind('.');
85- if (dot == std::string::npos)
86- return {name, ""};
87- return {name.substr(0, dot), name.substr(dot + 1)};
88-}
89- 
90-std::string qualifyOp(const std::string& op, const std::string& form) { return form.empty() ? op : op + "." + form; }
91- 
92-void applyUarchParam(UarchConfig& uarch, std::string_view key, std::string_view type, std::string_view value)
93-{
94- (void)type;
95- const std::string keyText = toString(key);
96- const auto intIt = std::find_if(
97- kIntUarchParams.begin(), kIntUarchParams.end(), [&](const auto& param) { return param.key == keyText; });
98- if (intIt != kIntUarchParams.end()) {
99- uarch.*(intIt->member) = parseInt(value);
100- return;
101- }
102- 
103- const auto boolIt = std::find_if(
104- kBoolUarchParams.begin(), kBoolUarchParams.end(), [&](const auto& param) { return param.key == keyText; });
105- if (boolIt != kBoolUarchParams.end()) {
106- uarch.*(boolIt->member) = parseBool(value);
107- return;
108- }
109- 
110- if (keyText == "mem_bar_mode")
111- uarch.memBarMode = toString(value);
112-}
113- 
114-void addRelation(
115- std::unordered_map<DTypeName, std::unordered_map<OpName, std::unordered_map<OpName, int64_t>>>& byDtype,
116- std::unordered_map<std::string, std::unordered_map<std::string, int64_t>>& byForm, const std::string& lhs,
117- const std::string& rhs, int64_t cycles)
118-{
119- const auto [lhsOp, lhsForm] = splitQualifiedOp(lhs);
120- const auto [rhsOp, rhsForm] = splitQualifiedOp(rhs);
121- if (!lhsForm.empty()) {
122- byForm[lhs][rhs] = cycles;
123- if (rhsForm.empty() || rhsForm == lhsForm)
124- byDtype[lhsForm][lhsOp][rhsOp] = cycles;
125- return;
126- }
127- byDtype[lhs][rhsOp][rhsForm] = cycles;
128-}
129- 
130-} // namespace
131- 
132-ParamDB::ParamDB(std::filesystem::path baseDir) : baseDir_(resolveBaseDir(std::move(baseDir)))
133-{
134- for (const auto& param : generated::kIsaDefaultParams) {
135- const std::string key = toString(param.key);
136- if (key == "vf_startup_cost")
137- bundle_.isaDefaults.vfStartupCost = param.value;
138- else if (key == "vf_drain_cost")
139- bundle_.isaDefaults.vfDrainCost = param.value;
140- }
141- 
142- for (const auto& param : generated::kIsaInstParams) {
143- InstConfig config;
144- config.pipelineStartupCost = param.pipelineStartupCost;
145- config.latency = param.latency;
146- config.throughput = param.throughput;
147- config.pipelineDrainCost = param.pipelineDrainCost;
148- config.dataLoadCost = param.dataLoadCost;
149- config.dataStoreCost = param.dataStoreCost;
150- config.exu = toString(param.exu);
151- config.dispatchExu = toString(param.dispatchExu);
152- config.opClass = toString(param.opClass);
153- bundle_.isa[toString(param.op)][toString(param.form)] = std::move(config);
154- }
155- 
156- for (const auto& param : generated::kUarchParams)
157- applyUarchParam(bundle_.uarch, param.key, param.type, param.value);
158- 
159- for (const auto& param : generated::kForwardingParams)
160- addRelation(
161- bundle_.forwarding, bundle_.forwardingByForm, toString(param.lhs), toString(param.rhs), param.cycles);
162- 
163- for (const auto& param : generated::kInitiationIntervalParams)
164- addRelation(
165- bundle_.initiationInterval, bundle_.initiationIntervalByForm, toString(param.lhs), toString(param.rhs),
166- param.cycles);
167-}
168- 
169-std::filesystem::path ParamDB::resolveBaseDir(std::filesystem::path baseDir)
170-{
171- if (baseDir.empty())
172- return std::filesystem::absolute(std::filesystem::current_path());
173- return std::filesystem::absolute(std::move(baseDir));
174-}
175- 
176-bool ParamDB::hasInst(const std::string& op, const std::string& dtype) const
177-{
178- const auto opIt = bundle_.isa.find(op);
179- if (opIt == bundle_.isa.end())
180- return false;
181- return opIt->second.find(dtype) != opIt->second.end();
182-}
183- 
184-const InstConfig& ParamDB::inst(const std::string& op, const std::string& dtype) const
185-{
186- const auto opIt = bundle_.isa.find(op);
187- if (opIt == bundle_.isa.end())
188- throw std::runtime_error("Instruction not found: op=" + op + ", dtype=" + dtype);
189- const auto dtypeIt = opIt->second.find(dtype);
190- if (dtypeIt == opIt->second.end())
191- throw std::runtime_error("Instruction not found: op=" + op + ", dtype=" + dtype);
192- return dtypeIt->second;
193-}
194- 
195-int64_t ParamDB::forwardingCycles(const std::string& dtype, const std::string& prod, const std::string& cons) const
196-{
197- const auto dtypeIt = bundle_.forwarding.find(dtype);
198- if (dtypeIt != bundle_.forwarding.end()) {
199- const auto prodIt = dtypeIt->second.find(prod);
200- if (prodIt != dtypeIt->second.end()) {
201- const auto consIt = prodIt->second.find(cons);
202- if (consIt != prodIt->second.end())
203- return std::max<int64_t>(0, consIt->second);
204- }
205- }
206- const int64_t latency = hasInst(prod, dtype) ? inst(prod, dtype).latency : 0;
207- return std::max<int64_t>(0, latency - 3);
208-}
209- 
210-int64_t ParamDB::forwardingCycles(
211- const std::string& prod, const std::string& prodForm, const std::string& cons, const std::string& consForm) const
212-{
213- const auto prodIt = bundle_.forwardingByForm.find(qualifyOp(prod, prodForm));
214- if (prodIt != bundle_.forwardingByForm.end()) {
215- const auto consIt = prodIt->second.find(qualifyOp(cons, consForm));
216- if (consIt != prodIt->second.end())
217- return std::max<int64_t>(0, consIt->second);
218- }
219- if (prodForm == consForm)
220- return forwardingCycles(prodForm, prod, cons);
221- const int64_t latency = hasInst(prod, prodForm) ? inst(prod, prodForm).latency : 0;
222- return std::max<int64_t>(0, latency - 3);
223-}
224- 
225-int64_t ParamDB::initiationInterval(const std::string& dtype, const std::string& prev, const std::string& cur) const
226-{
227- const auto dtypeIt = bundle_.initiationInterval.find(dtype);
228- if (dtypeIt != bundle_.initiationInterval.end()) {
229- const auto prevIt = dtypeIt->second.find(prev);
230- if (prevIt != dtypeIt->second.end()) {
231- const auto curIt = prevIt->second.find(cur);
232- if (curIt != prevIt->second.end())
233- return std::max<int64_t>(1, curIt->second);
234- }
235- }
236- return 1;
237-}
238- 
239-int64_t ParamDB::initiationInterval(
240- const std::string& prev, const std::string& prevForm, const std::string& cur, const std::string& curForm) const
241-{
242- const auto prevIt = bundle_.initiationIntervalByForm.find(qualifyOp(prev, prevForm));
243- if (prevIt != bundle_.initiationIntervalByForm.end()) {
244- const auto curIt = prevIt->second.find(qualifyOp(cur, curForm));
245- if (curIt != prevIt->second.end())
246- return std::max<int64_t>(1, curIt->second);
247- }
248- if (prevForm == curForm)
249- return initiationInterval(prevForm, prev, cur);
250- return 1;
251-}
252- 
253-} // namespace vfsim
@@ -1,48 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_PARAM_DB_H
11-#define VFSIM_NATIVE_PARAM_DB_H
12- 
13-#include "pto/costmodel/a5/VfSim/ParamSchema.h"
14- 
15-#include <filesystem>
16-#include <string>
17- 
18-namespace vfsim {
19- 
20-class ParamDB {
21-public:
22- explicit ParamDB(std::filesystem::path baseDir = {});
23- 
24- const ParamBundle& bundle() const noexcept { return bundle_; }
25- const UarchConfig& uarch() const noexcept { return bundle_.uarch; }
26- const IsaDefaults& isaDefaults() const noexcept { return bundle_.isaDefaults; }
27- 
28- bool hasInst(const std::string& op, const std::string& dtype) const;
29- const InstConfig& inst(const std::string& op, const std::string& dtype) const;
30- 
31- int64_t forwardingCycles(const std::string& dtype, const std::string& prod, const std::string& cons) const;
32- int64_t forwardingCycles(
33- const std::string& prod, const std::string& prodForm, const std::string& cons,
34- const std::string& consForm) const;
35- int64_t initiationInterval(const std::string& dtype, const std::string& prev, const std::string& cur) const;
36- int64_t initiationInterval(
37- const std::string& prev, const std::string& prevForm, const std::string& cur, const std::string& curForm) const;
38- 
39- static std::filesystem::path resolveBaseDir(std::filesystem::path baseDir);
40- 
41-private:
42- ParamBundle bundle_;
43- std::filesystem::path baseDir_;
44-};
45- 
46-} // namespace vfsim
47- 
48-#endif // VFSIM_NATIVE_PARAM_DB_H
@@ -1,91 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_PARAM_SCHEMA_H
11-#define VFSIM_NATIVE_PARAM_SCHEMA_H
12- 
13-#include <cstdint>
14-#include <string>
15-#include <unordered_map>
16- 
17-namespace vfsim {
18- 
19-struct InstConfig {
20- int64_t pipelineStartupCost = 0;
21- int64_t latency = 0;
22- int64_t throughput = 0;
23- int64_t pipelineDrainCost = 0;
24- int64_t dataLoadCost = 0;
25- int64_t dataStoreCost = 0;
26- std::string exu;
27- std::string dispatchExu;
28- std::string opClass;
29-};
30- 
31-struct IsaDefaults {
32- int64_t vfStartupCost = 0;
33- int64_t vfDrainCost = 0;
34-};
35- 
36-struct UarchConfig {
37- int64_t issuePorts = 0;
38- int64_t loadPorts = 0;
39- int64_t storePorts = 0;
40- int64_t iduWindowWidth = 0;
41- int64_t iduIssueWidth = 0;
42- int64_t ldqWidth = 0;
43- int64_t vregNum = 0;
44- bool enableIsuQueueModel = false;
45- int64_t shqDepth = 0;
46- int64_t exqDepth = 0;
47- bool admitBlockedToExq = false;
48- bool enableShqCreditModel = false;
49- int64_t shqReleaseDelay = 0;
50- bool enableCreditVisibilityDelay = false;
51- int64_t iduVisiblePregDelay = 0;
52- int64_t iduVisibleShqDelay = 0;
53- bool globalShqPregGate = false;
54- bool useExplicitIduCreditBank = false;
55- int64_t iduToOooDelay = 0;
56- int64_t vloopToDispatchDelay = 0;
57- int64_t iduDispatchStartAdvance = 0;
58- int64_t initialTopBlockVloopStartCycle = 0;
59- int64_t nestedVloopInitialStartGap = 0;
60- int64_t loop1MinFeedbackGap = 0;
61- int64_t innermostIterDispatchStride = 0;
62- int64_t consumerReleaseStartOffset = 0;
63- int64_t loadDoneLatency = 0;
64- int64_t oooToShqDelay = 0;
65- int64_t oooToLsqDelay = 0;
66- int64_t exqRecvDelay = 0;
67- int64_t shqToExqPortPerCycle = 0;
68- int64_t computeInflightCap = 0;
69- int64_t exqIssueInflightCapPerPort = 0;
70- bool exqCapacityCountsInflight = false;
71- std::string memBarMode;
72- bool enforceSameCycleSrcHazard = false;
73- bool enableCrossFuIi = false;
74-};
75- 
76-using DTypeName = std::string;
77-using OpName = std::string;
78- 
79-struct ParamBundle {
80- IsaDefaults isaDefaults;
81- std::unordered_map<OpName, std::unordered_map<DTypeName, InstConfig>> isa;
82- std::unordered_map<DTypeName, std::unordered_map<OpName, std::unordered_map<OpName, int64_t>>> forwarding;
83- std::unordered_map<DTypeName, std::unordered_map<OpName, std::unordered_map<OpName, int64_t>>> initiationInterval;
84- std::unordered_map<std::string, std::unordered_map<std::string, int64_t>> forwardingByForm;
85- std::unordered_map<std::string, std::unordered_map<std::string, int64_t>> initiationIntervalByForm;
86- UarchConfig uarch;
87-};
88- 
89-} // namespace vfsim
90- 
91-#endif // VFSIM_NATIVE_PARAM_SCHEMA_H
@@ -1,204 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#include "pto/costmodel/a5/VfSim/ProgramAnalysis.h"
11- 
12-#include <algorithm>
13-#include <cctype>
14-#include <stdexcept>
15-#include <utility>
16- 
17-namespace vfsim {
18-namespace {
19- 
20-bool isDigits(const std::string& text)
21-{
22- if (text.empty())
23- return false;
24- return std::all_of(text.begin(), text.end(), [](unsigned char c) { return std::isdigit(c) != 0; });
25-}
26- 
27-} // namespace
28- 
29-ProgramNode ProgramNode::makeInst(ProgramInstNode value)
30-{
31- ProgramNode node;
32- node.kind = Kind::Inst;
33- node.inst = std::move(value);
34- node.loop.reset();
35- return node;
36-}
37- 
38-ProgramNode ProgramNode::makeLoop(ProgramLoopNode value)
39-{
40- ProgramNode node;
41- node.kind = Kind::Loop;
42- node.loop = std::make_shared<ProgramLoopNode>(std::move(value));
43- return node;
44-}
45- 
46-ProgramAnalysis::ProgramAnalysis(ParamMap params, std::unordered_map<std::string, ValueInfo> values)
47- : params_(std::move(params)), values_(std::move(values))
48-{}
49- 
50-bool ProgramAnalysis::isVregName(const std::string& name) const
51-{
52- auto it = values_.find(name);
53- if (it != values_.end())
54- return it->second.storage == ValueStorageKind::Register;
55- const std::string suffix = "_lane";
56- const auto pos = name.rfind(suffix);
57- if (pos != std::string::npos && pos + suffix.size() < name.size()) {
58- bool digits = true;
59- for (size_t i = pos + suffix.size(); i < name.size(); ++i) {
60- if (!std::isdigit(static_cast<unsigned char>(name[i]))) {
61- digits = false;
62- break;
63- }
64- }
65- if (digits) {
66- it = values_.find(name.substr(0, pos));
67- if (it != values_.end())
68- return it->second.storage == ValueStorageKind::Register;
69- }
70- }
71- return inferValueStorage(name) == ValueStorageKind::Register;
72-}
73- 
74-int64_t ProgramAnalysis::resolveBound(const std::string& bound) const
75-{
76- if (isDigits(bound))
77- return std::stoll(bound);
78- auto it = params_.find(bound);
79- if (it != params_.end())
80- return it->second;
81- throw std::invalid_argument("Unsupported loop bound: " + bound);
82-}
83- 
84-int64_t ProgramAnalysis::resolveUnrollValue(const std::string& unroll) const
85-{
86- if (isDigits(unroll))
87- return std::max<int64_t>(1, std::stoll(unroll));
88- auto it = params_.find(unroll);
89- if (it != params_.end())
90- return std::max<int64_t>(1, it->second);
91- return 1;
92-}
93- 
94-void ProgramAnalysis::collectVregsFromInst(
95- const ProgramInstNode& inst, std::unordered_map<std::string, bool>& vregs) const
96-{
97- for (const auto& name : inst.src) {
98- if (isVregName(name))
99- vregs.emplace(name, true);
100- }
101- for (const auto& name : inst.dst) {
102- if (isVregName(name))
103- vregs.emplace(name, true);
104- }
105-}
106- 
107-void ProgramAnalysis::walkVregWarnings(
108- const std::vector<ProgramNode>& nodes, const std::string& path, int64_t pregNum,
109- std::vector<VregCapacityWarning>& warnings) const
110-{
111- int loopIndex = 0;
112- for (const auto& node : nodes) {
113- if (node.kind != ProgramNode::Kind::Loop || !node.loop)
114- continue;
115- 
116- ++loopIndex;
117- const ProgramLoopNode& loop = *node.loop;
118- const std::string loopPath = path + ".loop" + std::to_string(loopIndex);
119- const int64_t unroll = resolveUnrollValue(loop.unroll);
120- 
121- std::unordered_map<std::string, bool> vregs;
122- std::vector<const ProgramNode*> stack;
123- for (const auto& child : loop.body)
124- stack.push_back(&child);
125- 
126- while (!stack.empty()) {
127- const ProgramNode* cur = stack.back();
128- stack.pop_back();
129- if (cur->kind == ProgramNode::Kind::Inst) {
130- collectVregsFromInst(cur->inst, vregs);
131- continue;
132- }
133- if (cur->loop) {
134- for (const auto& child : cur->loop->body)
135- stack.push_back(&child);
136- }
137- }
138- 
139- const int64_t baseVregNamespace = static_cast<int64_t>(vregs.size());
140- const int64_t expandedVregNamespace = baseVregNamespace * std::max<int64_t>(1, unroll);
141- if (expandedVregNamespace > pregNum) {
142- warnings.push_back(VregCapacityWarning{
143- "vreg_namespace_overflow_risk",
144- loopPath,
145- pregNum,
146- baseVregNamespace,
147- unroll,
148- expandedVregNamespace,
149- "Unroll-expanded virtual-register namespace exceeds physical register count. Prediction may be "
150- "low-confidence for this case.",
151- });
152- }
153- 
154- walkVregWarnings(loop.body, loopPath, pregNum, warnings);
155- }
156-}
157- 
158-std::vector<VregCapacityWarning> ProgramAnalysis::collectVregCapacityWarnings(
159- const std::vector<ProgramNode>& program, int64_t pregNum) const
160-{
161- std::vector<VregCapacityWarning> warnings;
162- walkVregWarnings(program, "program", pregNum, warnings);
163- return warnings;
164-}
165- 
166-std::vector<int64_t> ProgramAnalysis::inferNestedBoundsFromLoop(const ProgramLoopNode& loop) const
167-{
168- std::vector<int64_t> bounds;
169- const ProgramLoopNode* cur = &loop;
170- 
171- while (cur != nullptr && bounds.size() < 3) {
172- bounds.push_back(resolveBound(cur->iters));
173- const ProgramLoopNode* nextLoop = nullptr;
174- for (const auto& node : cur->body) {
175- if (node.kind == ProgramNode::Kind::Loop && node.loop) {
176- nextLoop = node.loop.get();
177- break;
178- }
179- }
180- cur = nextLoop;
181- }
182- 
183- return bounds;
184-}
185- 
186-std::unordered_map<int, std::vector<int64_t>> ProgramAnalysis::inferTopBlockLoopBounds(
187- const std::vector<ProgramNode>& program) const
188-{
189- std::unordered_map<int, std::vector<int64_t>> result;
190- int tbid = 0;
191- 
192- for (const auto& node : program) {
193- if (node.kind == ProgramNode::Kind::Loop && node.loop) {
194- result.emplace(tbid++, inferNestedBoundsFromLoop(*node.loop));
195- }
196- }
197- 
198- if (result.empty())
199- result.emplace(0, std::vector<int64_t>{});
200- 
201- return result;
202-}
203- 
204-} // namespace vfsim
@@ -1,65 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_PROGRAM_ANALYSIS_H
11-#define VFSIM_NATIVE_PROGRAM_ANALYSIS_H
12- 
13-#include <cstdint>
14-#include "pto/costmodel/a5/VfSim/VfInfo.h"
15- 
16-#include <string>
17-#include <unordered_map>
18-#include <vector>
19- 
20-namespace vfsim {
21- 
22-struct VregCapacityWarning {
23- std::string kind;
24- std::string loopPath;
25- int64_t pregNum = 0;
26- int64_t baseVregNamespace = 0;
27- int64_t unroll = 1;
28- int64_t expandedVregNamespace = 0;
29- std::string message;
30-};
31- 
32-class ProgramAnalysis {
33-public:
34- using ParamMap = std::unordered_map<std::string, int64_t>;
35- 
36- explicit ProgramAnalysis(ParamMap params = {}, std::unordered_map<std::string, ValueInfo> values = {});
37- 
38- bool isVregName(const std::string& name) const;
39- 
40- int64_t resolveBound(const std::string& bound) const;
41- int64_t resolveUnrollValue(const std::string& unroll) const;
42- 
43- std::vector<VregCapacityWarning> collectVregCapacityWarnings(
44- const std::vector<ProgramNode>& program, int64_t pregNum) const;
45- 
46- std::vector<int64_t> inferNestedBoundsFromLoop(const ProgramLoopNode& loop) const;
47- 
48- std::unordered_map<int, std::vector<int64_t>> inferTopBlockLoopBounds(
49- const std::vector<ProgramNode>& program) const;
50- 
51- const ParamMap& params() const noexcept { return params_; }
52- 
53-private:
54- ParamMap params_;
55- std::unordered_map<std::string, ValueInfo> values_;
56- 
57- void collectVregsFromInst(const ProgramInstNode& inst, std::unordered_map<std::string, bool>& vregs) const;
58- void walkVregWarnings(
59- const std::vector<ProgramNode>& nodes, const std::string& path, int64_t pregNum,
60- std::vector<VregCapacityWarning>& warnings) const;
61-};
62- 
63-} // namespace vfsim
64- 
65-#endif // VFSIM_NATIVE_PROGRAM_ANALYSIS_H
@@ -1,95 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#include "pto/costmodel/a5/VfSim/ProgramCanonicalization.h"
11- 
12-#include <utility>
13- 
14-namespace vfsim {
15-namespace {
16- 
17-std::vector<std::string> renameLane(const std::vector<std::string>& values, int64_t lane)
18-{
19- std::vector<std::string> renamed;
20- renamed.reserve(values.size());
21- for (const auto& value : values)
22- renamed.push_back(value + "_lane" + std::to_string(lane));
23- return renamed;
24-}
25- 
26-std::vector<ProgramNode> expandBody(const std::vector<ProgramNode>& body, int64_t unroll)
27-{
28- std::vector<ProgramNode> expanded;
29- expanded.reserve(body.size() * static_cast<size_t>(unroll));
30- for (const auto& node : body) {
31- for (int64_t lane = 0; lane < unroll; ++lane) {
32- ProgramInstNode clone = node.inst;
33- clone.src = renameLane(node.inst.src, lane);
34- clone.dst = renameLane(node.inst.dst, lane);
35- expanded.push_back(ProgramNode::makeInst(std::move(clone)));
36- }
37- }
38- return expanded;
39-}
40- 
41-bool isInstructionOnlyBody(const std::vector<ProgramNode>& body)
42-{
43- for (const auto& node : body) {
44- if (node.kind != ProgramNode::Kind::Inst)
45- return false;
46- }
47- return true;
48-}
49- 
50-std::vector<ProgramNode> rewrite(
51- const std::vector<ProgramNode>& nodes, const ProgramAnalysis& analysis, ProgramCanonicalizationStats& stats)
52-{
53- std::vector<ProgramNode> out;
54- for (const auto& node : nodes) {
55- if (node.kind != ProgramNode::Kind::Loop || !node.loop) {
56- out.push_back(node);
57- continue;
58- }
59- 
60- const ProgramLoopNode& loop = *node.loop;
61- const int64_t iters = analysis.resolveBound(loop.iters);
62- const int64_t unroll = analysis.resolveUnrollValue(loop.unroll);
63- const bool shouldExpand = iters == 1 || (unroll > 1 && iters == unroll);
64- if (isInstructionOnlyBody(loop.body) && shouldExpand) {
65- auto expanded = expandBody(loop.body, unroll);
66- ++stats.expandedLoops;
67- stats.expandedInstructions += static_cast<int64_t>(expanded.size());
68- out.insert(out.end(), std::make_move_iterator(expanded.begin()), std::make_move_iterator(expanded.end()));
69- continue;
70- }
71- 
72- ProgramLoopNode rewritten = loop;
73- rewritten.body = rewrite(loop.body, analysis, stats);
74- out.push_back(ProgramNode::makeLoop(std::move(rewritten)));
75- }
76- return out;
77-}
78- 
79-} // namespace
80- 
81-std::vector<ProgramNode> canonicalizeSingleSuperIterationLoops(
82- const std::vector<ProgramNode>& program, const ProgramAnalysis::ParamMap& params, const ParamDB& db,
83- const std::string& dtype, ProgramCanonicalizationStats* stats)
84-{
85- (void)db;
86- (void)dtype;
87- ProgramCanonicalizationStats localStats;
88- ProgramAnalysis analysis(params);
89- auto rewritten = rewrite(program, analysis, localStats);
90- if (stats != nullptr)
91- *stats = localStats;
92- return rewritten;
93-}
94- 
95-} // namespace vfsim
@@ -1,33 +0,0 @@
1-/**
2-Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4-CANN Open Software License Agreement Version 2.0 (the "License").
5-Please refer to the License for details. You may not use this file except in compliance with the License.
6-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7-INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8-See LICENSE in the root of the software repository for the full text of the License.
9-*/
10-#ifndef VFSIM_NATIVE_PROGRAM_CANONICALIZATION_H
11-#define VFSIM_NATIVE_PROGRAM_CANONICALIZATION_H
12- 
13-#include "pto/costmodel/a5/VfSim/ParamDB.h"
14-#include "pto/costmodel/a5/VfSim/ProgramAnalysis.h"
15- 
16-#include <cstdint>
17-#include <string>
18-#include <vector>
19- 
20-namespace vfsim {
21- 
22-struct ProgramCanonicalizationStats {
23- int64_t expandedLoops = 0;
24- int64_t expandedInstructions = 0;
25-};
26- 
27-std::vector<ProgramNode> canonicalizeSingleSuperIterationLoops(
28- const std::vector<ProgramNode>& program, const ProgramAnalysis::ParamMap& params, const ParamDB& db,
29- const std::string& dtype = "fp32", ProgramCanonicalizationStats* stats = nullptr);
30- 
31-} // namespace vfsim
32- 
33-#endif // VFSIM_NATIVE_PROGRAM_CANONICALIZATION_H