This is an archive of the discontinued LLVM Phabricator instance.

[flang] Use internal linkage for string literals
ClosedPublic

Authored by DavidTruby on May 4 2023, 8:40 AM.

Details

Summary

On Windows, global string literals with "linkonce" linkage is not
supported without using comdat. As a simpler fix than adding comdat
support we can use internal linkage instead.

This fixes a bug where two string literals with the same value in
different fortran files would cause a linker error due to the use
of linkonce linkage.

Diff Detail

Event Timeline

DavidTruby created this revision.May 4 2023, 8:40 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptMay 4 2023, 8:40 AM
DavidTruby requested review of this revision.May 4 2023, 8:40 AM

As a simpler fix than adding comdat support ...

Do you know at which stages we would need to add comdat exactly (is this something that is lacking in MLIR LLVM dialect only)?

This fixes a bug where two string literals with the same value in different fortran files would cause a linker error due to the use of linkonce linkage.

Was this bug happening outside of windows too?

My overall thought: we do not need the linkonce for correctness purpose here, and I am not sure how much binary size this actually allow saving (the only case I can think of is the one where a module would define a huge PARAMETER string that would be used in many different compilation units), so, I would be OK to drop it for strings.

But there is another case where we use linkonce_odr and actually need it for correctness purposes: derived type descriptor for types defined in modules.

The runtime requires that two instance of the same derived type in the same program have the same derived type descriptor address. We cannot emit derived type descriptors with external in the module that is defining them because that will not be possible with parametrized derived types, where the instance may be done in different compilation units (derived type descriptors depends on kind parameter values). So I do not think there is a way around comdat here.

https://github.com/llvm/llvm-project/blob/8df5913250d55883feb8fa46a838c93a77c2e291/flang/lib/Lower/ConvertVariable.cpp#L529
https://github.com/llvm/llvm-project/blob/9470169fcbe93ccf9f97b56bfb23c636e32133d8/flang/runtime/derived-api.cpp#L104

Essentially, at an LLVM IR level, for each global variable with linkonce linkage you need a comdat declaration for linkage to work on Windows. For example:

$foo = comdat any
@foo = linkonce constant [5 x i8] c"hello"

MLIR's LLVM dialect doesn't seem to support the comdat construct here so we would need to add support there. I think this is only needed for Windows but from what I can tell it's just ignored on other platforms so we could just add it every time we have a linkonce global.

I was concerned when posting this patch that we do use linkonce elsewhere and will need to consider this for those usages too, but this fixes a specific bug we are seeing. Once we have comdat support I think using linkonce for strings is also fine, so we could revert this.

I can look in to how difficult adding the comdat construct would be

I'm currently working on adding support for comdat to MLIR. Would you be ok with merging this to fix the string bug while I am working on that?

jeanPerier accepted this revision.May 11 2023, 12:49 AM

I'm currently working on adding support for comdat to MLIR. Would you be ok with merging this to fix the string bug while I am working on that?

Thanks for working on comdat!
And yes, you can merge this, but please add a TODO comment near createInternalLinkage that we will want to go back to linkonce/linkonce_odr when comdat is supported.

This revision is now accepted and ready to land.May 11 2023, 12:49 AM
This revision was landed with ongoing or failed builds.May 11 2023, 7:47 AM
This revision was automatically updated to reflect the committed changes.