Skip to content

[mlir] Add pass to add comdat to all linkonce functions #65270

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

Merged
merged 1 commit into from
Sep 13, 2023

Conversation

DavidTruby
Copy link
Member

@DavidTruby DavidTruby commented Sep 4, 2023

This adds a new pass to add an Any comdat to each linkonce
and linkonce_odr function in the LLVM dialect. These comdats are necessary on Windows
to allow the default system linker to link binaries containing these functions.

@DavidTruby DavidTruby requested a review from a team as a code owner September 4, 2023 15:30
@DavidTruby
Copy link
Member Author

I'm not really sure this is the best way to do it in general, I wanted to post for comments really. I think a linkage-like comdat attribute on FuncOp would possibly be better in the long run so that languages/conversions that need this behaviour can add it granularly, although we may still want the option to add it for everything for users that don't care and just want linking to work.

Doing it like this does fix our use case in flang, as we would be one of the aforementioned non-bothered users :)

@DavidTruby
Copy link
Member Author

The exact use case in flang is that we just want every function that has linkonce or linkonce_odr linkage to have the Any comdat on any target that supports comdats (well, particularly on Windows where linking won't work at all without them, but behaviour is also slightly better on ELF-based platforms with comdats than without them).

We particularly see this when converting using the MathToFuncs dialects where ipowi operations are converted using a function defined by the conversion with linkonce linkage, and so these fail to link on Windows with the default linker because it bails on the duplicate definitions with no comdats. If comdats could be added to FuncOps at any point, MathToFuncs could just add the comdat when compiling for a target that supports comdats.

@DavidTruby
Copy link
Member Author

DavidTruby commented Sep 6, 2023

As regards auto-detecting this based on the target somehow, that was suggested in https://reviews.llvm.org/D127455 but was rejected as an approach as not wanting to default to that for everyone and give each frontend more fine-grained control. A blanket option is still quite a blunt instrument but is sufficient for a lot of use cases (including flang's), but I agree with the attached review that it should be an option rather than always forced and auto-detected.

@joker-eph
Copy link
Collaborator

Can you make this a separate pass?

@DavidTruby DavidTruby requested a review from a team as a code owner September 6, 2023 16:45
@github-actions github-actions bot added mlir:core MLIR Core Infrastructure mlir labels Sep 6, 2023
@DavidTruby DavidTruby changed the title [mlir] Add option to add comdat to all linkonce functions [mlir] Add pass to add comdat to all linkonce functions Sep 6, 2023
@@ -0,0 +1,17 @@
// RUN: mlir-opt -llvm-add-comdats -verify-diagnostics %s | FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this test reside in mlir/test/Dialect/LLVMIR/ ?

@@ -0,0 +1,78 @@
//===- AddComdats.cpp - Prepare for translation to LLVM IR ----------------===//
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: The description here sounds odd.

RewritePatternSet patterns(ctx);
patterns.add<AddComdat>(ctx);
if (failed(
applyPatternsAndFoldGreedily(getOperation(), std::move(patterns))))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Using patterns is far too expensive and overkill for what is a simple traversal here I think.

Seems like this Pass should:

  1. run on a SymbolOpInterface (most of the time the module).
  2. Build a symbol table once and for all.
  3. Iterated on the immediately nested operation and do a single traversal.

Copy link
Member Author

Choose a reason for hiding this comment

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

I wasn't sure how to run just on the SymbolOpInterface, if I specify that in Passes.td then things don't compile.
It seems to work just traversing over the module though.

Copy link
Collaborator

Choose a reason for hiding this comment

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

You are still missing on 2. : "Build a symbol table once and for all"

@DavidTruby DavidTruby requested a review from a team as a code owner September 8, 2023 12:45
void runOnOperation() override {
OpBuilder builder{&getContext()};
ModuleOp mod = getOperation();
mod.walk([&](LLVM::LLVMFuncOp op) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The walk is recursive here, we should just iterate: for (auto op = mod.getOperations<LLVM::LLVMFuncOp>())

RewritePatternSet patterns(ctx);
patterns.add<AddComdat>(ctx);
if (failed(
applyPatternsAndFoldGreedily(getOperation(), std::move(patterns))))
Copy link
Collaborator

Choose a reason for hiding this comment

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

You are still missing on 2. : "Build a symbol table once and for all"

ModuleOp &module) {
const char *comdatName = "__llvm_comdat";
mlir::LLVM::ComdatOp comdatOp =
module.lookupSymbol<mlir::LLVM::ComdatOp>(comdatName);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This lookup should use the symbolTable built in runOnOperation

@@ -45,12 +46,13 @@ struct AddComdatsPass : public LLVM::impl::LLVMAddComdatsBase<AddComdatsPass> {
void runOnOperation() override {
OpBuilder builder{&getContext()};
ModuleOp mod = getOperation();
mod.walk([&](LLVM::LLVMFuncOp op) {
SymbolTable symbolTable{mod};
Copy link
Collaborator

Choose a reason for hiding this comment

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

One slight more tweak, can we make this lazy? Maybe:

std::unique_ptr<SymbolTable> symbolTable;
auto getSymTab = [&] () -> SymbolTable& {
  if (!symbolTable)
    symbolTable = std::make_unique<SymbolTable>(mod);
  return *symbolTable;
};

And then you can call addComdat(op, builder, getSymTab(), mod);

Copy link
Collaborator

@joker-eph joker-eph left a comment

Choose a reason for hiding this comment

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

Thanks for indulging all the edits :)

This adds a pass operating on the LLVMIR dialect to add an Any comdat to each
linkonce and linkonce_odr function when lowering. These comdats are necessary on
Windows to allow the default system linker to link binaries containing these
functions.
@DavidTruby DavidTruby merged commit a685715 into llvm:main Sep 13, 2023
@DavidTruby
Copy link
Member Author

The Windows CI seems broken on all patches so I've merged regardless.

Thanks for indulging all the edits :)

No problem, I hadn't written an MLIR pass before so it's good to learn the correct way of doing things! Thanks for the comments.

ZijunZhaoCCK pushed a commit to ZijunZhaoCCK/llvm-project that referenced this pull request Sep 19, 2023
This adds a new pass to add an Any comdat to each linkonce
and linkonce_odr function in the LLVM dialect. These comdats are
necessary on Windows
to allow the default system linker to link binaries containing these
functions.
@omjavaid omjavaid added this to the LLVM 17.0.X Release milestone Oct 12, 2023
tru pushed a commit that referenced this pull request Oct 31, 2023
This adds a new pass to add an Any comdat to each linkonce
and linkonce_odr function in the LLVM dialect. These comdats are
necessary on Windows
to allow the default system linker to link binaries containing these
functions.

(cherry picked from commit a685715)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:core MLIR Core Infrastructure mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants