This is an archive of the discontinued LLVM Phabricator instance.

[flang] Add ExternalNameConversionPass to flang-new pipeline
ClosedPublic

Authored by rovka on Mar 7 2022, 3:48 PM.

Details

Summary

This seems to be the consensus in
https://github.com/flang-compiler/f18-llvm-project/issues/1316

The patch adds ExternalNameConversion to the default FIR CodeGen pass
pipeline, right before the FIRtoLLVM pass. It also adds a flag to optionally
disable it, and sets it in tco. In other words, flang-new and flang-new -fc1
will both run the pass by default, whereas tco will not, so none of the tests
need to be updated.

Diff Detail

Event Timeline

rovka created this revision.Mar 7 2022, 3:48 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 7 2022, 3:48 PM
Herald added a subscriber: jdoerfert. · View Herald Transcript
rovka requested review of this revision.Mar 7 2022, 3:48 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 7 2022, 3:48 PM

Thanks for working on this, @rovka!

There's one more alternative. ExternalNameConversionPass has a rather huge and visible impact on the generated output. It makes sense to have it enabled by default, but you could also add a flag (e.g. -finternal-mangling or some other spelling) to disable it. This way:

  • you'd only have to update RUN lines in tests, and
  • we'd have a "compatibility" mode for bbc and flang-new, which IMO would be a good thing for reproducibility.

This would mean an extra if statement in CodeGenAction::BeginSourceFileAction, but that would still be rather straightforward. And the pass pipeline definitions are bound to become more complex and require refactoring at some point anyway (we've not discussed -O{0|1|2|3} yet).

I agree that we should have a dedicated test to verify that this pass is run. Dumping the pass pipeline would be fantastic and perhaps MLIR already supports that? (I haven't checked, but I suspect that it does). A dedicated flag to disable this pass would also make it easy to write a test.

WDYT?

There's one more alternative. ExternalNameConversionPass has a rather huge and visible impact on the generated output. It makes sense to have it enabled by default, but you could also add a flag (e.g. -finternal-mangling or some other spelling) to disable it. This way:

  • you'd only have to update RUN lines in tests, and
  • we'd have a "compatibility" mode for bbc and flang-new, which IMO would be a good thing for reproducibility.

+1

schweitz added a comment.EditedMar 9 2022, 7:39 AM

The internal mangling is stable. Target-specific mangling is not. We don't want to write all tests that get top heavy and tricky to maintain dealing with distractions like target conformance and compatibility rather than focusing on what they ought to be testing.

Note: The Windows naming convention is a bit different again and would not match here.

flang/test/Lower/Intrinsics/abs.f90
2 ↗(On Diff #413649)

Why does this test need to be run with flang?

We don't see the LLVM tests being driven by both opt and clang.

awarzynski added inline comments.Mar 9 2022, 8:05 AM
flang/test/Lower/Intrinsics/abs.f90
2 ↗(On Diff #413649)

We don't see the LLVM tests being driven by both opt and clang.

That would require LLVM depending on Clang. Also, opt is for testing (and setting up) each LLVM pass individually. Clang neither needs nor supports this level of granularity. Instead, it operates at higher abstraction level, e.g. different optimisation pipelines. The situation with flang-new and bbc is very different.

schweitz added inline comments.Mar 9 2022, 8:18 AM
flang/test/Lower/Intrinsics/abs.f90
2 ↗(On Diff #413649)

BTW, something appears to be incorrect here.

Is -emit-fir on flang supposed to behave the same way as it always has with the lowering test tool, bbc? The codegen pass to convert symbols to some target for compatibility is not part of lowering and isn't reflected in the lowering output which is what bbc -emit-fir produces.

So it looks like flang -emit-fir and bbc -emit-fir have already diverged here. Is that the intention? If so, then flang certainly cannot replace bbc.

schweitz added inline comments.Mar 9 2022, 8:28 AM
flang/test/Lower/Intrinsics/abs.f90
2 ↗(On Diff #413649)

That would require LLVM depending on Clang. Also, opt is for testing (and setting up) each LLVM pass individually. Clang neither needs nor supports this level of granularity. Instead, it operates at higher abstraction level, e.g. different optimisation pipelines. The situation with flang-new and bbc is very different.

Disagree. bbc is a test tool that is intended to test lowering. Specifically, the conversion of the PFT, plus other data structures, to FIR. The purpose of the flang-new driver is to be a Fortran compiler end-to-end. Those two objectives are absolutely, positively different.

There is clearly confusion on this point. That likely stems from the fact that the only way to pickle the PFT (and other data) is to pretty print it out as Fortran. That perfect circularity makes it appear that bbc is trying to be something it was not intended to be.

Can we stop conflating these two purposes?

pmccormick added inline comments.Mar 9 2022, 8:53 AM
flang/test/Lower/Intrinsics/abs.f90
2 ↗(On Diff #413649)

@schweitz -- thanks for the clarification on bbc. I have to admit I was confused by the differences/similarities. Its appearance in use cases that don't feel that different from the driver have probably helped add to the confusion (at least mine! ;-).

Should we consider some way to make this distinction more clear for those new to the code base? I suspect there is a longer history here behind bbc but being more specific about its intended usage might help us avoid revisiting this again down the road; especially so for those new to the code base and the supporting toolset.

awarzynski added inline comments.Mar 9 2022, 9:19 AM
flang/test/Lower/Intrinsics/abs.f90
2 ↗(On Diff #413649)

@schweitz , @pmccormick The motivations for developing bbc and flang-new were different: bbc was developed to test lowering, flang-new was introduced as the end-to-end compiler driver. However, we reached a point where bbc and flang-new overlap in functionality. Strongly. Both bbc and flang-new consume Fortran source and lower it to MLIR. I'm not aware of anything that bbc can do that flang-new couldn't. The fact that we can replace bbc with flang-new in tests demonstrates this point. So yes, the motivations for creating bbc and flang-new were different, but the available functionality is not.

Anyway, I think that we are diverging here. A lot :) IIRC, this patch is to discuss ExternalNameConversionPass.

So it looks like flang -emit-fir and bbc -emit-fir have already diverged here.

Not yet and I agree that we should avoid this :) IIRC, this patch (in its current form) simply demonstrates one approach to facilitate the discussion. @rovka suggested 2 approaches - both would lead to flang-new and bbc being incompatible. I suggested 3rd approach, which would keep the 2 tools interchangeable. We are yet to decide which approach to take :)

rovka added inline comments.Mar 10 2022, 5:09 AM
flang/test/Lower/Intrinsics/abs.f90
2 ↗(On Diff #413649)

I'm not aware of anything that bbc can do that flang-new couldn't.

In fact there seem to be things that flang-new can do that bbc can't (see this comment). But that's probably for a different patch.

So it looks like flang -emit-fir and bbc -emit-fir have already diverged here. Is that the intention?

No, in light of the above discussion I'm starting to think this wasn't the right place to add the pass. Since you say it's a codegen pass, would it make more sense for it to be run as part of the defaultFIRCodeGenPassPipeline? Or do we want to keep it just in the driver, maybe right before the other MLIRToLLVM passes?

rovka updated this revision to Diff 415788.Mar 16 2022, 5:52 AM
rovka edited the summary of this revision. (Show Details)

Take 2 :)

This is adding ExternalNameConversion to the default FIR codegen pipeline, right before the FIRtoLLVM pass. This means we're no longer affecting bbc in any way, and also tco and flang-new will both be running it. I think I'm remembering from previous discussions that we do want tco and flang-new to be consistent about their behaviour, and this is a surefire way to achieve that (they're both calling createMLIRToLLVMPassPipeline, which in turn is calling createDefaultFIRCodeGenPassPipeline).

I think this is a good place to put it because

  1. it works on FIR specifically, so we can't run it any later than this, and
  2. we probably don't want other FIR passes to worry about what kind of mangling is being used, so it's best to put it last.

There's one lowering test that needs updating, because it's calling bbc | tco. I'm not sure why it needs this end-to-end behaviour, but if it really does I'm guessing it's better to let it run the default passes and update the test accordingly than to explicitly disable this pass.

Do we still want to add a flag to optionally disable this pass?
Also, do we want to move the pass from flang/Optimizer/Transforms/Passes.td to flang/Optimizer/Codegen/CGPasses.td, to clarify that it's a codegen pass?

clementval added inline comments.Apr 1 2022, 12:41 AM
flang/include/flang/Tools/CLOptions.inc
64–66

We might want to add a disable option as well for this pass.

schweitz added inline comments.Apr 1 2022, 10:23 AM
flang/test/Lower/Intrinsics/abs.f90
6 ↗(On Diff #413649)

Thanks @rovka for moving the pass to the default code gen passes. That's great.

Again, this CHECKing isn't going to work for Windows interoperability since the mangling of Fortran procedure names is different there. (Yes, even Fortran 77.) To future-proof this, we should allow bbc and flang-new to use different check lines rather than CHECKs that try to hit the intersection. I don't think it will be at all harmful to CHECK both the internal uniqued names (via bbc) and whatever exotic compatibility modes (via flang-new) come down the pike in the future. In fact, that seems quite desirable. :)

schweitz added inline comments.Apr 1 2022, 10:25 AM
flang/test/Lower/Intrinsics/abs.f90
2 ↗(On Diff #413649)

@pmccormick - Yes, the distinction should be documented more precisely and clearly.

Thanks for driving this, Diana!

This is adding ExternalNameConversion to the default FIR codegen pipeline, right before the FIRtoLLVM pass.

Makes sense to me.

There's one lowering test that needs updating, because it's calling bbc | tco. I'm not sure why it needs this end-to-end behaviour, but if it really does I'm guessing it's better to let it run the default passes and update the test accordingly than to explicitly disable this pass.

IMO it would make a lot of sense to use flang-new -fc1 -emit-llvm for this test. That would make the intent clearer (i.e. that the goal is to verify the generated LLVM IR). On a di

Do we still want to add a flag to optionally disable this pass?

Depends on our end goal here. @schweitz mentioned Windows interoperability. I guess that the mangling will be different on other platforms too? We could add the flag to disable ExternalNameConversionPass and then use it in tests so that:

  • all tests will auto-magically work on Windows (or any other platform that we care about),
  • we won't be adding extra check lines for different mangling (we would require 1 per every supported platform).

We wouldn't use the flag in tests that verify the mangling itself. But otherwise, it would be always set. In general, I think that it would be nice to avoid:

  • requiring people to write different CHECK lines for different drivers (unless we are verifying that the behavior in some specific scenario is indeed different),
  • using regex in CHECK-LABEL (it will be just easier for everyone if we don't).

Having said all that, we don't seem to need this flag just now :) But it would be nice to agree what to check in CHECK-LABEL.

Also, do we want to move the pass from flang/Optimizer/Transforms/Passes.td to flang/Optimizer/Codegen/CGPasses.td, to clarify that it's a codegen pass?

+1

clementval added a comment.EditedApr 4 2022, 4:46 AM

Also, do we want to move the pass from flang/Optimizer/Transforms/Passes.td to flang/Optimizer/Codegen/CGPasses.td, to clarify that it's a codegen pass?

Not sure on that. It doesn't codegen anything and the input/output are both FIR so it's more a generic pass to me. Including it later in the pipeline doesn't change that it is generic for any FIR inputs.

clementval added a comment.EditedApr 4 2022, 4:48 AM

Do we still want to add a flag to optionally disable this pass?

Depends on our end goal here. @schweitz mentioned Windows interoperability. I guess that the mangling will be different on other platforms too? We could add the flag to disable ExternalNameConversionPass and then use it in tests so that:

Most of the passes have a disable option when included in the pipeline. I agree that we might not need it right now but why delay a one line option that will for sure be useful in development and testing.

rovka added a comment.Apr 4 2022, 5:51 AM

Do we still want to add a flag to optionally disable this pass?

Depends on our end goal here. @schweitz mentioned Windows interoperability. I guess that the mangling will be different on other platforms too? We could add the flag to disable ExternalNameConversionPass and then use it in tests so that:

Most of the passes have a disable option when included in the pipeline. I agree that we might not need it right now but why delay a one line option that will for sure be useful in development and testing.

That sounds like a good idea to me, I'll add an option and use it in this test. I'll send a new patch probably tomorrow or so.

Thanks for all the comments so far!

Most of the passes have a disable option when included in the pipeline. I agree that we might not need it right now but why delay a one line option that will for sure be useful in development and testing.

For testing specific passes, we can already use fir-opt. And if we want this pass to be controlled with a flag, then we will need to add it separately in flang-new and tco. That's going to be more than one line. In general, I think that using fir-opt in such scenarios (instead of introducing extra flags) is cleaner and clearer.

I'm also wondering - if mangling is going to be platform specific, then perhaps we need options to specify the platform to mangle for instead? This way, we can specify in tests:

! RUN: flang-new -fc1 -internal-name-mangling=linux -emit-llvm file.f90

This way, we would be able to keep our tests platform-agnostic (and everything would be future proof). This would also be more flexible than plain "disable"/"enable" toggle. WDTY?

rovka added a comment.Apr 5 2022, 1:17 AM

Most of the passes have a disable option when included in the pipeline. I agree that we might not need it right now but why delay a one line option that will for sure be useful in development and testing.

For testing specific passes, we can already use fir-opt. And if we want this pass to be controlled with a flag, then we will need to add it separately in flang-new and tco. That's going to be more than one line. In general, I think that using fir-opt in such scenarios (instead of introducing extra flags) is cleaner and clearer.

We already use fir-opt to test this pass (see here and here).

I'm also wondering - if mangling is going to be platform specific, then perhaps we need options to specify the platform to mangle for instead? This way, we can specify in tests:

! RUN: flang-new -fc1 -internal-name-mangling=linux -emit-llvm file.f90

This way, we would be able to keep our tests platform-agnostic (and everything would be future proof). This would also be more flexible than plain "disable"/"enable" toggle. WDTY?

I think that's out of scope for this patch. AFAICT the pass doesn't yet do anything platform specific. When we add support for another kind of mangling, then we can decide how to control it (I would opt for handling it the same way we did for TargetRewrite, but there's not much point discussing it right now). Having a flag in tco to disable the pass altogether seems like an orthogonal issue to me, and it would be consistent with the other passes to provide it. I'm uploading a new version of the patch so you can see what I mean (it's only a bit more than one line).

rovka updated this revision to Diff 420406.Apr 5 2022, 1:19 AM

Added a flag to tco to disable the pass, and used it in the test (which means we no longer need to modify it).
I'm still trying to figure out if I can get tco and flang-new to dump the pass pipeline that they're running, so we can check that the pass is indeed added.

rovka updated this revision to Diff 420466.Apr 5 2022, 5:37 AM

Added a test for tco's default pass pipeline. This is hijacking the MLIR pass manager's capabilities for printing statistics, because I couldn't find something more direct. Would be nice to add something like this for flang-new as well. @awarzynski does flang-new have something that can forward options to MLIR? (I'm thinking of something like -mllvm)

awarzynski added a comment.EditedApr 5 2022, 6:06 AM

Note that without this change, "flang/test/Lower/common-block.f90" can be run with both bbc/tco and flang-new. This change removes this possibility. We pledged to retire bbc/tco in favour of flang-new/fir-opt and this change is a step in the opposite direction (at least in it's current format) . I think that we should maintain the interoperability of tests using bbc/tco and flang-new.

@awarzynski does flang-new have something that can forward options to MLIR? (I'm thinking of something like -mllvm)

I've recently added -mllvm, but I've not had the chance to look at -mmlir. To me, it would make sense to add it first and to make sure that "basic-program.fir" works with both tco and flang-new.

Edit: I suspect that with -mmlir, you might be able to use the options from CLOptions.inc in flang-new. I haven't tried it yet myself.

We pledged to retire bbc/tco in favour of flang-new/fir-opt and this change is a step in the opposite direction (at least in it's current format) . I think that we should maintain the interoperability of tests using bbc/tco and flang-new.

Who made this pledge and why? Why the eagerness to cripple the core developers standard workflow on this project?

There was never any claims that bbc was identical to flang-new, because it simply is not. flang-new is, for one thing, a fully functional C++ compiler as well as accepting some Fortran.

schweitz added inline comments.Apr 5 2022, 8:52 AM
flang/test/Lower/common-block.f90
1 ↗(On Diff #420466)

This pass will have to be disabled in tco by default for tests to pass.

rovka updated this revision to Diff 420759.Apr 6 2022, 2:44 AM
  • Fix windows pre-commit checks (there was an issue about how 'anonymous namespace' is printed in one of the names of the passes, but that's not really relevant to the test anyway)
  • Rebase
rovka added a comment.Apr 6 2022, 3:04 AM

Note that without this change, "flang/test/Lower/common-block.f90" can be run with both bbc/tco and flang-new. This change removes this possibility. We pledged to retire bbc/tco in favour of flang-new/fir-opt and this change is a step in the opposite direction (at least in it's current format) . I think that we should maintain the interoperability of tests using bbc/tco and flang-new.

I'm very much in favor of keeping the interoperability (regardless of whether or not we're going to retire any of the tools). That's why I was asking about how to pass the same flag to flang-new.

@awarzynski does flang-new have something that can forward options to MLIR? (I'm thinking of something like -mllvm)

I've recently added -mllvm, but I've not had the chance to look at -mmlir. To me, it would make sense to add it first and to make sure that "basic-program.fir" works with both tco and flang-new.

Edit: I suspect that with -mmlir, you might be able to use the options from CLOptions.inc in flang-new. I haven't tried it yet myself.

I think adding -mmlir is the best way to handle this, but that should clearly be a separate patch.

In the meantime, we could add a temporary bandaid flag to flang-new for specifically disabling this pass, but I'm not sure if it's worth the effort, since this isn't the only tco flag that flang-new doesn't support (we already have tests in tree using e.g. --ignore-missing-type-desc or --fir-to-llvm-ir).

To be honest, I'm probably more interested in why these isolated tests need to run the whole pipeline in the first place. I'm not against end-to-end testing where it makes sense, but these 2 tests look like a pretty random subset and could use some comments about what exactly they're trying to achieve.

flang/test/Lower/common-block.f90
1 ↗(On Diff #420466)

Why? I thought the main purpose of a flag to disable the pass was to facilitate testing.
I'm working from the premise that we want to keep flang-new and tco compatible, which means that if we enable the pass by default in flang-new, we should enable it by default in tco as well.

I think adding -mmlir is the best way to handle this, but that should clearly be a separate patch.

I agree :) I gave it a go and here's the result: https://reviews.llvm.org/D123297

To be honest, I'm probably more interested in why these isolated tests need to run the whole pipeline in the first place. I'm not against end-to-end testing where it makes sense, but these 2 tests look like a pretty random subset and could use some comments about what exactly they're trying to achieve.

My thoughts exactly.

rovka updated this revision to Diff 421493.Apr 8 2022, 5:16 AM
rovka edited the summary of this revision. (Show Details)
rovka set the repository for this revision to rG LLVM Github Monorepo.

Added test for flang-new pass pipeline (MLIR passes only).

rovka added inline comments.Apr 8 2022, 5:20 AM
flang/test/Driver/pass-pipeline.f90
33 ↗(On Diff #421493)

It seems tco and flang-new lower from the LLVM dialect to LLVM IR slightly differently. tco uses a pass, but flang-new doesn't. I put this check here in case we ever switch flang-new to use the pass, like tco does.

awarzynski added inline comments.Apr 11 2022, 3:16 AM
flang/test/Driver/pass-pipeline.f90
33 ↗(On Diff #421493)

It seems tco and flang-new lower from the LLVM dialect to LLVM IR slightly differently.

Good catch! This particular pass is effectively a wrapper for mlir::translateModuleToLLVMIR that unconditionally prints the output. So in practice this pass does two things:

  • lower from MLIR LLVM IR to LLVM IR
  • print the generated LLVM IR

In flang-new, the two actions are separated. mlir::translateModuleToLLVMIR is run here. Printing is then done e.g. here.

rovka updated this revision to Diff 422447.Apr 13 2022, 2:58 AM

Update test after https://reviews.llvm.org/D123495 (new names for MLIR options).

schweitz added inline comments.Apr 22 2022, 10:34 AM
flang/test/Fir/embox.fir
1 ↗(On Diff #422447)

I don't understand why running a fir-opt nullary execution is needed.

flang/test/Lower/common-block.f90
1 ↗(On Diff #420466)

That's not the right premise. tco doesn't need to be in lock-step with the official compiler because it is intended to solve separable problems. I don't want artificial barriers and specious objectives introduced into the test tool. The fact they can be used independently and may produce differing output is actually a good thing.

rovka added inline comments.Apr 27 2022, 1:13 AM
flang/test/Fir/embox.fir
1 ↗(On Diff #422447)

Me neither, that's just how the test was written. I only updated the tco execution so that the test preserves its previous behaviour.

rovka updated this revision to Diff 425712.Apr 28 2022, 1:28 AM
rovka edited the summary of this revision. (Show Details)

Disabled the pass in tco, so the tests no longer need to be updated.

Ping?

Sorry for the delay and thanks for driving this!

The current approach sounds like a good compromise to me. It does mean that we will need to use -external-name-interop when using flang-new alongside tco in tests. If that becomes too painful, we can always introduce a dedicated LIT variable or revisit this altogether.

A test using flang-new that exercises -external-name-interop would be nice :) Otherwise, LGTM!

flang/test/Driver/pass-pipeline.f90
3 ↗(On Diff #425712)

[nit] Why not rename the file as mlir-pass-pipeline.f90 and remove this FIXME? We definitely should test the LLVM pipeline too, but for that we will need a different command line flag.

rovka updated this revision to Diff 426974.May 4 2022, 5:54 AM
rovka edited the summary of this revision. (Show Details)

Addressed Andrzej's comments. Thanks :)

awarzynski accepted this revision.May 4 2022, 6:48 AM

LGTM :) @schweitz, does this work for you?

This revision is now accepted and ready to land.May 4 2022, 6:48 AM
schweitz accepted this revision.May 5 2022, 10:45 AM
This revision was automatically updated to reflect the committed changes.