Skip to content

Conversation

@Jackcuii
Copy link
Collaborator

Just a draft up till now. can build, but has runtime bugs to be solved

@Jackcuii Jackcuii changed the title successfully built, read spec path from ENV Arch-aware Mapping (successfully built, read spec path from ENV) Jul 31, 2025
Copy link
Contributor

Copilot AI left a 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
Comment on lines 12 to 19
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'))
Copy link

Copilot AI Jul 31, 2025

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.

Suggested change
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', '')))

Copilot uses AI. Check for mistakes.
Copy link
Contributor

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;
Copy link

Copilot AI Jul 31, 2025

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.

Suggested change
use_default_arch = true;

Copilot uses AI. Check for mistakes.
}
} catch (const std::exception& e) {
llvm::errs() << "[MapToAcceleratorPass] Error parsing YAML file "
<< arch_spec_path << ": " << e.what() << ", using default 4x4\n";
Copy link

Copilot AI Jul 31, 2025

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.

Suggested change
<< arch_spec_path << ": " << e.what() << ", using default 4x4\n";
<< arch_spec_path << ": " << e.what() << ", using default 4x4\n";
use_default_arch = true;

Copilot uses AI. Check for mistakes.
Comment on lines +278 to +292
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;
Copy link

Copilot AI Jul 31, 2025

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.

Suggested change
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();

Copilot uses AI. Check for mistakes.
// 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));
Copy link

Copilot AI Jul 31, 2025

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.

Suggested change
tile->addFunctionUnit(std::make_unique<FixedPointAdder>(++fu_id));
tile->addFunctionUnit(std::make_unique<FixedPointAdder>(fu_id++));

Copilot uses AI. Check for mistakes.
Copy link
Contributor

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));
Copy link

Copilot AI Jul 31, 2025

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.

Suggested change
tile->addFunctionUnit(std::make_unique<FixedPointAdder>(++fu_id));
tile->addFunctionUnit(std::make_unique<FixedPointAdder>(fu_id++));

Copilot uses AI. Check for mistakes.
Copy link
Contributor

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,
Copy link

Copilot AI Jul 31, 2025

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.

Copilot uses AI. Check for mistakes.
@tancheng
Copy link
Contributor

@Jackcuii is this PR ready for review? If yes, @ShangkunLi plz help review. Otherwise, plz first make this PR pass github action.

@Jackcuii
Copy link
Collaborator Author

Jackcuii commented Jul 31, 2025

@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.

@tancheng
Copy link
Contributor

tancheng commented Aug 4, 2025

@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 instruction.json provided by @n0thingNoob, but here you are relying on yaml. So do we really need two formats?

@Jackcuii
Copy link
Collaborator Author

Jackcuii commented Aug 5, 2025

@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 instruction.json provided by @n0thingNoob, but here you are relying on yaml. So do we really need two formats?

The yaml here is the description of architecture.
Accroding to my understanding, the instruction.json is the generated instruction sequence

@tancheng
Copy link
Contributor

tancheng commented Aug 5, 2025

@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 instruction.json provided by @n0thingNoob, but here you are relying on yaml. So do we really need two formats?

The yaml here is the description of architecture. Accroding to my understanding, the instruction.json is the generated instruction sequence

My question is can we only use one format for all? Each format would increase the codebase by introducing library and header files.

@n0thingNoob
Copy link
Collaborator

@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 instruction.json provided by @n0thingNoob, but here you are relying on yaml. So do we really need two formats?

The yaml here is the description of architecture. Accroding to my understanding, the instruction.json is the generated instruction sequence

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.

@n0thingNoob
Copy link
Collaborator

Do I also need to change the codegenpass? Since it is also generating json file.

@tancheng
Copy link
Contributor

tancheng commented Aug 6, 2025

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
Copy link
Contributor

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
Copy link
Contributor

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.

Copy link
Collaborator Author

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.

Comment on lines 58 to 59
Br_ = 22,
CondBr_ = 23,
Copy link
Contributor

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++?

Copy link
Collaborator Author

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.

Copy link
Contributor

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.

Copy link
Collaborator Author

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));
Copy link
Contributor

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));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Comment on lines 152 to 182
// 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";
}
Copy link
Contributor

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);
Copy link
Contributor

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);

Copy link
Collaborator Author

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

Copy link
Contributor

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome~!

Jackcui and others added 3 commits August 10, 2025 19:50
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_;
Copy link
Collaborator

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?

Copy link
Collaborator Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants