-
Notifications
You must be signed in to change notification settings - Fork 14
Arch-aware Mapping (successfully built, read spec path from ENV) #101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces architecture-aware mapping functionality by implementing YAML-based configuration for the hardware architecture specification. The implementation allows reading architecture details from an environment variable instead of using hardcoded values.
- Added YAML configuration support for flexible architecture specification
- Extended operation kind mappings to support more MLIR operations
- Enhanced the MapToAcceleratorPass to read architecture from environment variables
Reviewed Changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| test/lit.cfg | Added LIT test configuration with hardcoded tool paths |
| lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp | Implemented YAML-based architecture loading from environment variable |
| lib/NeuraDialect/Mapping/mapping_util.cpp | Extended operation kind mapping to support additional MLIR operations |
| lib/NeuraDialect/CMakeLists.txt | Added yaml-cpp dependency and exception handling |
| lib/NeuraDialect/Architecture/Architecture.cpp | Implemented YAML constructor for Architecture class |
| include/NeuraDialect/Architecture/Architecture.h | Extended OperationKind enum and added YAML constructor declaration |
| CMakeLists.txt | Added yaml-cpp dependency and global exception handling |
test/lit.cfg
Outdated
| config.substitutions.append(('mlir-neura-opt', '/home/jackcui/Arch/MLiR/dataflow/build/tools/mlir-neura-opt/mlir-neura-opt')) | ||
| config.substitutions.append(('neura-interpreter', '/home/jackcui/Arch/MLiR/dataflow/build/tools/neura-interpreter/neura-interpreter')) | ||
| config.substitutions.append(('neura-compiler', '/home/jackcui/Arch/MLiR/dataflow/build/tools/neura-compiler/neura-compiler')) | ||
| config.substitutions.append(('FileCheck', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/FileCheck')) | ||
| config.substitutions.append(('mlir-opt', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/mlir-opt')) | ||
| config.substitutions.append(('mlir-translate', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/mlir-translate')) | ||
| config.substitutions.append(('llc', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/llc')) | ||
| config.substitutions.append(('clang', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/clang')) |
Copilot
AI
Jul 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded absolute paths make the configuration non-portable across different development environments. Consider using relative paths or environment variables to make this configuration more flexible.
| config.substitutions.append(('mlir-neura-opt', '/home/jackcui/Arch/MLiR/dataflow/build/tools/mlir-neura-opt/mlir-neura-opt')) | |
| config.substitutions.append(('neura-interpreter', '/home/jackcui/Arch/MLiR/dataflow/build/tools/neura-interpreter/neura-interpreter')) | |
| config.substitutions.append(('neura-compiler', '/home/jackcui/Arch/MLiR/dataflow/build/tools/neura-compiler/neura-compiler')) | |
| config.substitutions.append(('FileCheck', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/FileCheck')) | |
| config.substitutions.append(('mlir-opt', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/mlir-opt')) | |
| config.substitutions.append(('mlir-translate', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/mlir-translate')) | |
| config.substitutions.append(('llc', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/llc')) | |
| config.substitutions.append(('clang', '/home/jackcui/Arch/MLiR/llvm-project/build/./bin/clang')) | |
| config.substitutions.append(('mlir-neura-opt', os.getenv('MLIR_NEURA_OPT_PATH', ''))) | |
| config.substitutions.append(('neura-interpreter', os.getenv('NEURA_INTERPRETER_PATH', ''))) | |
| config.substitutions.append(('neura-compiler', os.getenv('NEURA_COMPILER_PATH', ''))) | |
| config.substitutions.append(('FileCheck', os.getenv('FILECHECK_PATH', ''))) | |
| config.substitutions.append(('mlir-opt', os.getenv('MLIR_OPT_PATH', ''))) | |
| config.substitutions.append(('mlir-translate', os.getenv('MLIR_TRANSLATE_PATH', ''))) | |
| config.substitutions.append(('llc', os.getenv('LLC_PATH', ''))) | |
| config.substitutions.append(('clang', os.getenv('CLANG_PATH', ''))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't check in this file. Similarly, plz remove all the build files. avoid using git add .
| } else { | ||
| llvm::errs() << "[MapToAcceleratorPass] Could not open architecture file " | ||
| << arch_spec_path << ", using default 4x4\n"; | ||
| use_default_arch = true; |
Copilot
AI
Jul 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable use_default_arch is set to true when the file cannot be opened, but this assignment is redundant since use_default_arch is already initialized to false and should remain false to trigger the YAML-based architecture creation.
| use_default_arch = true; |
| } | ||
| } catch (const std::exception& e) { | ||
| llvm::errs() << "[MapToAcceleratorPass] Error parsing YAML file " | ||
| << arch_spec_path << ": " << e.what() << ", using default 4x4\n"; |
Copilot
AI
Jul 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When YAML parsing fails, the code should set use_default_arch = true to ensure the default architecture is used, but this assignment is missing.
| << arch_spec_path << ": " << e.what() << ", using default 4x4\n"; | |
| << arch_spec_path << ": " << e.what() << ", using default 4x4\n"; | |
| use_default_arch = true; |
| Architecture::Architecture(const YAML::Node& config) { | ||
| // Extract width and height from config | ||
| int width = 4; // default | ||
| int height = 4; // default | ||
|
|
||
| if (config["architecture"] && config["architecture"]["width"] && config["architecture"]["height"]) { | ||
| width = config["architecture"]["width"].as<int>(); | ||
| height = config["architecture"]["height"].as<int>(); | ||
| } | ||
|
|
||
| // Call the constructor with width and height. | ||
| *this = Architecture(width, height); | ||
|
|
||
| // Add function units based on the architecture specs. | ||
| int num_tiles = width * height; |
Copilot
AI
Jul 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using assignment operator on *this in a constructor is problematic and can lead to undefined behavior. Consider using constructor delegation or member initialization instead.
| Architecture::Architecture(const YAML::Node& config) { | |
| // Extract width and height from config | |
| int width = 4; // default | |
| int height = 4; // default | |
| if (config["architecture"] && config["architecture"]["width"] && config["architecture"]["height"]) { | |
| width = config["architecture"]["width"].as<int>(); | |
| height = config["architecture"]["height"].as<int>(); | |
| } | |
| // Call the constructor with width and height. | |
| *this = Architecture(width, height); | |
| // Add function units based on the architecture specs. | |
| int num_tiles = width * height; | |
| Architecture::Architecture(const YAML::Node& config) | |
| : Architecture( | |
| config["architecture"] && config["architecture"]["width"] && config["architecture"]["height"] | |
| ? config["architecture"]["width"].as<int>() | |
| : 4, | |
| config["architecture"] && config["architecture"]["height"] | |
| ? config["architecture"]["height"].as<int>() | |
| : 4) { | |
| // Add function units based on the architecture specs. | |
| int num_tiles = getNumTiles(); |
| // Override the default function units. | ||
| for (const auto& operation : config["tile_overrides"][i]["operations"]) { | ||
| if (operation.as<std::string>() == "add") { | ||
| tile->addFunctionUnit(std::make_unique<FixedPointAdder>(++fu_id)); |
Copilot
AI
Jul 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable fu_id is pre-incremented before use, which means the first function unit will have ID 1 instead of 0. This inconsistency could cause issues if function unit IDs are expected to start from 0.
| tile->addFunctionUnit(std::make_unique<FixedPointAdder>(++fu_id)); | |
| tile->addFunctionUnit(std::make_unique<FixedPointAdder>(fu_id++)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think copilot's suggestion makes sense?
| // Add default function units. | ||
| for (const auto& operation : config["tile_defaults"]["operations"]) { | ||
| if (operation.as<std::string>() == "add") { | ||
| tile->addFunctionUnit(std::make_unique<FixedPointAdder>(++fu_id)); |
Copilot
AI
Jul 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as above - fu_id should be post-incremented or the logic should be adjusted to start from 0.
| tile->addFunctionUnit(std::make_unique<FixedPointAdder>(++fu_id)); | |
| tile->addFunctionUnit(std::make_unique<FixedPointAdder>(fu_id++)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
| FMulFAdd = 9, | ||
| VFMul = 10, | ||
| ICmp = 11, | ||
| FCmp = 12, |
Copilot
AI
Jul 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The FCmp operation is defined in the enum but not handled in the getOperationKindFromMlirOp function in mapping_util.cpp, which could lead to incorrect operation mapping.
|
@Jackcuii is this PR ready for review? If yes, @ShangkunLi plz help review. Otherwise, plz first make this PR pass github action. |
Hi Sir Tan, it seems I need some more time on it before review. And maybe we should adapt the Github Action to install the yaml library. |
CCing @n0thingNoob I saw |
The yaml here is the description of architecture. |
My question is can we only use one format for all? Each format would increase the codebase by introducing library and header files. |
Sorry for the late reply, we can just use yaml. I can delete the instruction.json later. |
|
Do I also need to change the codegenpass? Since it is also generating json file. |
Sure, if that's not hard for you. And it seems our arch spec is also having both yaml and json, so we can remove json there as well? |
.gitignore
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't check in this file.
| Constant = 30, | ||
| DataMov = 31, | ||
| CtrlMov = 32, | ||
| Reserve = 33 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't actually map Reserve, in other words, Reserve is just a placeholder to facilitate mapping, no HW needed to support it. Similarly, DataMov and CtrlMov are data movement, which would be data path traversing links/channels, not sure we need them or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I keep Data/CtrlMov temporarily then.
| Br_ = 22, | ||
| CondBr_ = 23, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why we need _? Br and CondBr are reserved in C++?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that it will conflict with the MLIR library built-in if we do not use '_'? The compiler feedback is not quite informative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about OpBr and OpCondBr? i.e., Op prefix for all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure~
| // Override the default function units. | ||
| for (const auto& operation : config["tile_overrides"][i]["operations"]) { | ||
| if (operation.as<std::string>() == "add") { | ||
| tile->addFunctionUnit(std::make_unique<FixedPointAdder>(++fu_id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think copilot's suggestion makes sense?
| // Add default function units. | ||
| for (const auto& operation : config["tile_defaults"]["operations"]) { | ||
| if (operation.as<std::string>() == "add") { | ||
| tile->addFunctionUnit(std::make_unique<FixedPointAdder>(++fu_id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
| // Read architecture specification from command line option | ||
| YAML::Node config; | ||
| bool use_default_arch = false; | ||
|
|
||
| if (!archSpecPath.getValue().empty()) { | ||
| try { | ||
| std::ifstream file(archSpecPath.getValue()); | ||
| if (file.is_open()) { | ||
| config = YAML::Load(file); | ||
| if (config["architecture"]) { | ||
| llvm::outs() << "\033[31m[MapToAcceleratorPass] Loaded architecture from " | ||
| << archSpecPath.getValue() << "\033[0m\n"; | ||
| } else { | ||
| llvm::errs() << "[MapToAcceleratorPass] Invalid YAML format in " | ||
| << archSpecPath.getValue() << ", using default 4x4\n"; | ||
| use_default_arch = true; | ||
| } | ||
| } else { | ||
| llvm::errs() << "[MapToAcceleratorPass] Could not open architecture file " | ||
| << archSpecPath.getValue() << ", using default 4x4\n"; | ||
| use_default_arch = true; | ||
| } | ||
| } catch (const std::exception& e) { | ||
| llvm::errs() << "[MapToAcceleratorPass] Error parsing YAML file " | ||
| << archSpecPath.getValue() << ": " << e.what() << ", using default 4x4\n"; | ||
| use_default_arch = true; | ||
| } | ||
| } else { | ||
| use_default_arch = true; | ||
| llvm::errs() << "[MapToAcceleratorPass] No architecture specification provided, using default 4x4\n"; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put these into a function?
| llvm::errs() << "[MapToAcceleratorPass] No architecture specification provided, using default 4x4\n"; | ||
| } | ||
|
|
||
| Architecture architecture = use_default_arch ? Architecture(4, 4) : Architecture(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constexpr int kWidth = 4;
constexpr int kHeight = 4;
Architecture architecture = use_default_arch ? Architecture(kWidth, kHeight) : Architecture(config);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the problems above are fixed, but I can still not reproduce the environment problem. (even in a locally deployed Docker) a bit strange
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean yaml-related env problem cannot be fixed?
-- Configuring incomplete, errors occurred!
By not providing "Findyaml-cpp.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "yaml-cpp",
but CMake did not find one.
Could not find a package configuration file provided by "yaml-cpp" with any
of the following names:
yaml-cppConfig.cmake
yaml-cpp-config.cmake
Add the installation prefix of "yaml-cpp" to CMAKE_PREFIX_PATH or set
"yaml-cpp_DIR" to a directory containing one of the above files. If
"yaml-cpp" provides a separate development package or SDK, be sure it has
been installed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep. The main problem is that even with a totally clean Docker env, the problem does not occurs. And I am not sure what the real path of them in a blackbox workflow env.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw some one said libyaml-cpp-dev (instead of libyaml-dev) may work. Let me try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean yaml-related env problem cannot be fixed?
-- Configuring incomplete, errors occurred! By not providing "Findyaml-cpp.cmake" in CMAKE_MODULE_PATH this project has asked CMake to find a package configuration file provided by "yaml-cpp", but CMake did not find one. Could not find a package configuration file provided by "yaml-cpp" with any of the following names: yaml-cppConfig.cmake yaml-cpp-config.cmake Add the installation prefix of "yaml-cpp" to CMAKE_PREFIX_PATH or set "yaml-cpp_DIR" to a directory containing one of the above files. If "yaml-cpp" provides a separate development package or SDK, be sure it has been installed.
Cool. It seems to work! (Still something to be fixed :D)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome~!
update workflow to enable yaml cmake finding
| if (isa<neura::GrantAlwaysOp>(op)) return OpGrantAlways; | ||
| if (isa<neura::GrantOnceOp>(op)) return OpGrantOnce; | ||
| if (isa<neura::GrantPredicateOp>(op)) return OpGrantPredicate; | ||
| if (isa<neura::GEP>(op)) return OpGEP_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this line use OpGEP_ instead of OpGEP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. My mistake. should use OpGEP
Just a draft up till now. can build, but has runtime bugs to be solved