已合并
fix(costmodel): fix a5 vf costmodel implementation #1700
海王星创建于 9月17日
fix(costmodel): fix a5 vf costmodel implementation #1700
已合并
共 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 | ||