Skip to content

[MLIR][LLVMIR][DLTI] Add #llvm.target, #llvm.data_layout and TargetAttrInterface #145899

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

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

rolfmorel
Copy link
Contributor

No description provided.

@rolfmorel rolfmorel changed the title [MLIR][LLVMIR][DLTI] Add LLVMTargetAttrInterface, #llvm.target and #llvm.data_layout [MLIR][LLVMIR][DLTI] Add #llvm.target, #llvm.data_layout and TargetAttrInterface Jun 26, 2025
Copy link

github-actions bot commented Jun 26, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

return failure();
}

targetMachine = {target->createTargetMachine(
Copy link
Contributor Author

@rolfmorel rolfmorel Jun 26, 2025

Choose a reason for hiding this comment

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

@rengolin, what's the ownership model of TargetMachines? Should this attribute become the owner of this TargetMachine * by using a unique_ptr?

Copy link
Member

Choose a reason for hiding this comment

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

TargetMachine can be put into a unique_ptr, then reset using an llvm::Target::createTargetMachine and then use .get() to pass it to the LLVM pipeline builder.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I remembered why I didn't do it before: wrapping TargetMachine in a unique_ptr makes ODS-generated code, in particular a printer, scream:

In file included from /data/nfs_home/rmorel/llvm-project.git/llvm-target-dlti/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp:20:
/data/nfs_home/rmorel/llvm-project.git/llvm-target-dlti/llvm/include/llvm/ADT/TypeSwitch.h:102:29: error: call to implicitly-deleted copy constructor of 'mlir::LLVM::TargetAttr'
      result.emplace(caseFn(caseValue));
                            ^~~~~~~~~
tools/mlir/include/mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc:372:80: note: in instantiation of function template specialization 'llvm::TypeSwitch<mlir::Attribute, llvm::LogicalResult>::Case<mlir::LLVM::TargetAttr, (lambda at tools/mlir/include/mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc:372:111)>' requested here
  return ::llvm::TypeSwitch<::mlir::Attribute, ::llvm::LogicalResult>(def)    .Case<::mlir::LLVM::TargetAttr>([&](auto t) {
                                                                               ^
tools/mlir/include/mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.h.inc:306:55: note: copy constructor of 'TargetAttr' is implicitly deleted because field 'targetMachine' has a deleted copy constructor
  std::optional<std::unique_ptr<llvm::TargetMachine>> targetMachine = std::nullopt;
                                                      ^
/opt/rh/gcc-toolset-13/root/usr/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/optional:707:7: note: copy constructor of 'optional<std::unique_ptr<llvm::TargetMachine>>' is implicitly deleted because base class '_Enable_copy_move<is_copy_constructible_v<unique_ptr<TargetMachine, default_delete<TargetMachine>>>, __and_v<is_copy_constructible<unique_ptr<TargetMachine, default_delete<TargetMachine>>>, is_copy_assignable<unique_ptr<TargetMachine, default_delete<TargetMachine>>>>, is_move_constructible_v<unique_ptr<TargetMachine, default_delete<TargetMachine>>>, __and_v<is_move_constructible<unique_ptr<TargetMachine, default_delete<TargetMachine>>>, is_move_assignable<unique_ptr<TargetMachine, default_delete<TargetMachine>>>>, optional<unique_ptr<TargetMachine, default_delete<TargetMachine>>>>' has a deleted copy constructor
      private _Enable_copy_move<
      ^
/opt/rh/gcc-toolset-13/root/usr/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/enable_special_members.h:160:15: note: '_Enable_copy_move' has been explicitly marked deleted here
    constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept  = delete;
              ^
tools/mlir/include/mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc:372:120: note: passing argument to parameter 't' here
  return ::llvm::TypeSwitch<::mlir::Attribute, ::llvm::LogicalResult>(def)    .Case<::mlir::LLVM::TargetAttr>([&](auto t) {
                                                                                                                       ^
1 error generated.

This is with std::optional<std::unique_ptr<llvm::TargetMachine>> targetMachine = std::nullopt; in the extraClassDeclaration and

  auto targetMach = std::unique_ptr<llvm::TargetMachine>(target->createTargetMachine(
          llvm::Triple(getTriple().strref()), getChip().strref(),
          getFeatures().getFeaturesString().c_str(), {}, {}));

  targetMachine = { std::move(targetMach) };

in the implementation.

If I am understanding correctly, the issue seems to be that the type switch in the following code is trying to do a copy of the attribute, even though attributes should just be thought of/treated as (unique) pointers (... if my understanding is correct):

static ::llvm::LogicalResult generatedAttributePrinter(::mlir::Attribute def, ::mlir::AsmPrinter &printer) {
  return ::llvm::TypeSwitch<::mlir::Attribute, ::llvm::LogicalResult>(def)    .Case<::mlir::LLVM::TargetAttr>([&](auto t) {
      printer << ::mlir::LLVM::TargetAttr::getMnemonic();
t.print(printer);
      return ::mlir::success();
    })
    .Case<::mlir::LLVM::DataLayoutAttr>([&](auto t) {
      printer << ::mlir::LLVM::DataLayoutAttr::getMnemonic();
t.print(printer);
      return ::mlir::success();
    })
    .Case<::mlir::LLVM::CConvAttr>([&](auto t) 
    ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hopefully someone could help explain what the right way is to hang owned pointers off of an attribute.

Any and all pointers welcome!

// LLVM_TargetAttr
//===----------------------------------------------------------------------===//

def LLVM_TargetAttr : LLVM_Attr<"Target", "target", [LLVM_TargetAttrInterface]> {
Copy link
Contributor Author

@rolfmorel rolfmorel Jun 26, 2025

Choose a reason for hiding this comment

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

@rengolin, I am not sure what we want to do for verification here. Do we want to insist on the specified triple, cpu, and target_features being valid together. And do we verify that through constructing the relevant TargetMachine?

How would that work for dealing with IR which is annotated with a #llvm.target specifying a target that your current llvm-project isn't built with. Is it right that verification fails in that case? (Maybe it is, but it feels wrong as now verification succeeding or failing becomes a function of whether you built MLIR with the right flags.)

Copy link
Member

Choose a reason for hiding this comment

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

One problem we faced on our side earlier was that it's not that easy to know you're constructing an invalid TargetMachine (link). But validating all possible combinations is just not viable. For downstream targets, you'd have to overload some verification to match their alternatives.

Other tools don't verify much either (other than completely crash if the strings are invalid), so I guess we can start with that. The discussion about which combinations are valid (link) are generally higher in the pipeline (front-end). At the IR level, we can only treat them as "gospel" and crash if we really can't build a TargetMachine.

@rengolin rengolin requested review from ftynse and rengolin June 26, 2025 18:14
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.

2 participants