This is an archive of the discontinued LLVM Phabricator instance.

[MLIR] Fix autogenerated pass constructors linkage
ClosedPublic

Authored by mscuttari on Aug 24 2022, 9:57 AM.

Details

Summary

The patch addresses the linkage of the new autogenerated pass constructors, which, being declared as friend functions, resulted in having an inline nature and thus their implementations not being exported.

Diff Detail

Event Timeline

mscuttari created this revision.Aug 24 2022, 9:57 AM
Herald added a project: Restricted Project. · View Herald Transcript
mscuttari requested review of this revision.Aug 24 2022, 9:57 AM
mscuttari added a comment.EditedAug 24 2022, 9:59 AM

Compilation log (a bit trimmed, for clearness):

====================[ Build | check-mlir | Debug ]==============================
/Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake --build /Users/mscuttari/Desktop/llvm-project/llvm/cmake-build-debug --target check-mlir -j 8
[127/139] Linking CXX executable tools/mlir/unittests/ExecutionEngine/MLIRExecutionEngineTests

Undefined symbols for architecture arm64:
  "mlir::createConvertArithmeticToLLVMPass()", referenced from:
      lowerToLLVMDialect(mlir::ModuleOp) in Invoke.cpp.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

[130/139] Linking CXX executable bin/mlir-opt

Undefined symbols for architecture arm64:
  "mlir::createConvertArithmeticToLLVMPass()", referenced from:
      mlir::registerConvertArithmeticToLLVMPass()::'lambda'()::operator()() const in mlir-opt.cpp.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

[131/139] Linking CXX executable bin/mlir-capi-ir-test

Undefined symbols for architecture arm64:
  "mlir::createConvertArithmeticToLLVMPass()", referenced from:
      mlir::registerConvertArithmeticToLLVMPass()::'lambda'()::operator()() const in libMLIRCAPIRegisterEverything.a(RegisterEverything.cpp.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

[132/139] Linking CXX executable bin/mlir-reduce

Undefined symbols for architecture arm64:
  "mlir::createConvertArithmeticToLLVMPass()", referenced from:
      mlir::registerConvertArithmeticToLLVMPass()::'lambda'()::operator()() const in mlir-reduce.cpp.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

[133/139] Linking CXX executable bin/mlir-capi-execution-engine-test

Undefined symbols for architecture arm64:
  "mlir::createConvertArithmeticToLLVMPass()", referenced from:
      _mlirCreateConversionConvertArithmeticToLLVMPass in libMLIRCAPIConversion.a(Passes.cpp.o)
      mlir::registerConvertArithmeticToLLVMPass()::'lambda'()::operator()() const in libMLIRCAPIConversion.a(Passes.cpp.o)
      mlir::registerConvertArithmeticToLLVMPass()::'lambda'()::operator()() const in libMLIRCAPIRegisterEverything.a(RegisterEverything.cpp.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
[134/139] Linking CXX executable bin/mlir-cpu-runner
ninja: build stopped: subcommand failed.
rriddle added inline comments.Aug 24 2022, 10:01 AM
mlir/lib/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.cpp
21 ↗(On Diff #455260)

Is the base pass class being generated in the mlir namespace? It needs to be (the same as the namespace the create method is in).

mscuttari added inline comments.Aug 24 2022, 10:03 AM
mlir/lib/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.cpp
21 ↗(On Diff #455260)

Already tried (but uploaded the version without, as per original design intentions), didn't make any difference.

Wrapping the base class in mlir namespace. It is indeed the correct way to go, but still the
problem persists.

The issue is that the friend function in the class gets an inline linkage: it only gets emitted if it used in the translation unit.
I'm not sure if it can be made "not inline", usually you have to define it outside of the class but I don't know what the syntax would be here...

The issue is that the friend function in the class gets an inline linkage: it only gets emitted if it used in the translation unit.
I'm not sure if it can be made "not inline", usually you have to define it outside of the class but I don't know what the syntax would be here...

I've made a few tries but none of them solved the problem. What if we just go for the splitting of the macro? It seems to be we are trying to push the standard to its limits, with all the consequent risks.

The issue is that the friend function in the class gets an inline linkage: it only gets emitted if it used in the translation unit.
I'm not sure if it can be made "not inline", usually you have to define it outside of the class but I don't know what the syntax would be here...

I've made a few tries but none of them solved the problem. What if we just go for the splitting of the macro? It seems to be we are trying to push the standard to its limits, with all the consequent risks.

The inline linkage is specified in the standard it seems (I think): https://en.cppreference.com/w/cpp/language/friend

Defines a non-member function, and makes it a friend of this class at the same time. Such non-member function is always inline

If that's the case the easy fix would be to use an "Impl" function for the friend that is local, and just dispatch to that in the main create method:

std::unique_ptr<Pass> createFooImpl();

template <typename T>
class FooBase ... {
  friend std::unique_ptr<Pass> createFooImpl(...) {
    return std::make_unique<T>(...);
  }
};

std::unique_ptr<Pass> createFoo() {
  return createFooImpl();
}

That worked when I did it locally. I think if we really need to we should switch to 3 macros, but I think we should try as much as possible to limit the complexity necessary to define a single pass.

mscuttari retitled this revision from [MLIR] Split GEN_PASS_DEF to [MLIR] Fix autogenerated pass constructors linkage.Aug 26 2022, 12:18 AM
mscuttari edited the summary of this revision. (Show Details)

Add createPassNameImpl methods

mscuttari added a comment.EditedAug 26 2022, 12:21 AM

@rriddle thanks for the suggestion, working flawlessly. I have uploaded your fix and removed the changes I was doing to the passes, which I will instead upload in a separate patch in order to avoid a single commit mixing different stuff.

mehdi_amini accepted this revision.Aug 26 2022, 12:31 AM
This revision is now accepted and ready to land.Aug 26 2022, 12:31 AM
rriddle accepted this revision.Aug 26 2022, 12:50 AM

Nice! Do you think we should add a namespace field to the tablegen pass def now? Seems like that would be consistent with everything else (and would remove potential user foot guns as well).

Nice! Do you think we should add a namespace field to the tablegen pass def now? Seems like that would be consistent with everything else (and would remove potential user foot guns as well).

Sounds reasonable. Maybe a implnamespace for both the base class and the createPassNameImplmethods? At that point we can even rename createPassNameImplto just createPassName, as it would live in the implnamespace.

mscuttari updated this revision to Diff 455840.Aug 26 2022, 2:48 AM

impl namespace for pass base class and friend create constructors

@rriddle I'm sorry for the early ping, but I'm fixing the big patch regarding all the passes and I would like to know if the current namespace separation looks good. I'd like to avoid reiterating over all the passes just for this :D

The impl namespace seems fine to me, though we would need to update the docs to describe this. The docs should describe the ideal way to do things, and we can update the old uses in the codebase in the meantime.

mscuttari updated this revision to Diff 456287.Aug 29 2022, 1:58 AM

Update docs

mscuttari added a comment.EditedAug 29 2022, 2:07 AM

I've updated the docs. Feel free to comment on them if you feel them not to be clear enough.
In the meanwhile, I've uploaded a first draft regarding the patches to the pass declarations, so we can start discussing about them: D132838

This revision was automatically updated to reflect the committed changes.