-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[X86Backend][M68KBackend] Make Ctx in X86MCInstLower (M68KInstLower) the same as AsmPrinter.OutContext #133352
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
Changes from 9 commits
859ed81
5b74939
ec3e34e
cf82df0
fe9668b
a2433c9
e395289
e7dedc3
fc41f66
bc9791b
e4321ce
bf64c40
44dd9e3
14009cc
d504073
c3d31b2
b9dcf9a
1deea3b
65f158f
44cc5a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| //===- llvm/unittest/CodeGen/AArch64SelectionDAGTest.cpp | ||
|
||
| //-------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "../lib/Target/X86/X86ISelLowering.h" | ||
|
||
| #include "TestAsmPrinter.h" | ||
| #include "llvm/Analysis/MemoryLocation.h" | ||
| #include "llvm/Analysis/OptimizationRemarkEmitter.h" | ||
| #include "llvm/AsmParser/Parser.h" | ||
| #include "llvm/CodeGen/AsmPrinter.h" | ||
| #include "llvm/CodeGen/MachineModuleInfo.h" | ||
| #include "llvm/CodeGen/SelectionDAG.h" | ||
|
||
| #include "llvm/CodeGen/TargetLowering.h" | ||
| #include "llvm/CodeGen/TargetPassConfig.h" | ||
| #include "llvm/IR/LegacyPassManager.h" | ||
| #include "llvm/IR/MDBuilder.h" | ||
| #include "llvm/IR/Module.h" | ||
| #include "llvm/MC/MCStreamer.h" | ||
| #include "llvm/MC/TargetRegistry.h" | ||
| #include "llvm/Support/KnownBits.h" | ||
|
||
| #include "llvm/Support/SourceMgr.h" | ||
| #include "llvm/Support/TargetSelect.h" | ||
| #include "llvm/Target/TargetLoweringObjectFile.h" | ||
| #include "llvm/Target/TargetMachine.h" | ||
| #include "llvm/Testing/Support/Error.h" | ||
| #include "gmock/gmock.h" | ||
| #include "gtest/gtest.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class X86MCInstLowerTest : public testing::Test { | ||
| protected: | ||
| static void SetUpTestCase() { | ||
| LLVMInitializeX86TargetInfo(); | ||
|
||
| LLVMInitializeX86TargetMC(); | ||
| LLVMInitializeX86Target(); | ||
| LLVMInitializeX86AsmPrinter(); | ||
| } | ||
|
|
||
| // Function to setup codegen pipeline and returns the AsmPrinter. | ||
| AsmPrinter *addPassesToEmitFile(llvm::legacy::PassManagerBase &PM, | ||
| llvm::raw_pwrite_stream &Out, | ||
| llvm::CodeGenFileType FileType, | ||
| llvm::MachineModuleInfoWrapperPass *MMIWP) { | ||
| TargetPassConfig *PassConfig = TM->createPassConfig(PM); | ||
|
|
||
| PassConfig->setDisableVerify(true); | ||
| PM.add(PassConfig); | ||
| PM.add(MMIWP); | ||
|
|
||
| if (PassConfig->addISelPasses()) | ||
| return nullptr; | ||
|
|
||
| PassConfig->addMachinePasses(); | ||
| PassConfig->setInitialized(); | ||
|
|
||
| MC.reset(new MCContext(TM->getTargetTriple(), TM->getMCAsmInfo(), | ||
| TM->getMCRegisterInfo(), TM->getMCSubtargetInfo())); | ||
| MC->setObjectFileInfo(TM->getObjFileLowering()); | ||
| TM->getObjFileLowering()->Initialize(*MC, *TM); | ||
| MC->setObjectFileInfo(TM->getObjFileLowering()); | ||
|
|
||
| // Use a new MCContext for AsmPrinter for testing. | ||
| // AsmPrinter.OutContext will be different from | ||
| // MachineFunction's MCContext in MMIWP. | ||
| Expected<std::unique_ptr<MCStreamer>> MCStreamerOrErr = | ||
| TM->createMCStreamer(Out, nullptr, FileType, *MC); | ||
|
|
||
| if (auto Err = MCStreamerOrErr.takeError()) | ||
| return nullptr; | ||
|
|
||
| AsmPrinter *Printer = | ||
| TM->getTarget().createAsmPrinter(*TM, std::move(*MCStreamerOrErr)); | ||
|
|
||
| if (!Printer) | ||
| return nullptr; | ||
|
|
||
| PM.add(Printer); | ||
|
|
||
| return Printer; | ||
| } | ||
|
|
||
| void SetUp() override { | ||
| // Module to compile. | ||
| const char *FooStr = R""""( | ||
| @G = external global i32 | ||
| define i32 @foo() { | ||
| %1 = load i32, i32* @G; load the global variable | ||
| %2 = call i32 @f() | ||
| %3 = mul i32 %1, %2 | ||
| ret i32 %3 | ||
| } | ||
| declare i32 @f() #0 | ||
| )""""; | ||
| StringRef AssemblyF(FooStr); | ||
|
|
||
| // Get target triple for X86_64 | ||
| Triple TargetTriple("x86_64--"); | ||
| std::string Error; | ||
| const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); | ||
| if (!T) | ||
| GTEST_SKIP(); | ||
|
|
||
| // Get TargetMachine. | ||
| // Use Reloc::Model::PIC_ and CodeModel::Model::Large | ||
| // to get GOT during codegen as MO_ExternalSymbol. | ||
| TargetOptions Options; | ||
| TM = std::unique_ptr<TargetMachine>(T->createTargetMachine( | ||
| TargetTriple, "", "", Options, Reloc::Model::PIC_, | ||
| CodeModel::Model::Large, CodeGenOptLevel::Default)); | ||
| if (!TM) | ||
| GTEST_SKIP(); | ||
|
|
||
| SMDiagnostic SMError; | ||
|
|
||
| // Parse the module. | ||
| M = parseAssemblyString(AssemblyF, SMError, Context); | ||
| if (!M) | ||
| report_fatal_error(SMError.getMessage()); | ||
| M->setDataLayout(TM->createDataLayout()); | ||
|
|
||
| // Get llvm::Function from M | ||
| Foo = M->getFunction("foo"); | ||
| if (!Foo) | ||
| report_fatal_error("foo?"); | ||
|
|
||
| // Prepare the MCContext for codegen M. | ||
| // MachineFunction for Foo will have this MCContext. | ||
| MCFoo.reset(new MCContext(TargetTriple, TM->getMCAsmInfo(), | ||
| TM->getMCRegisterInfo(), | ||
| TM->getMCSubtargetInfo())); | ||
| MCFoo->setObjectFileInfo(TM->getObjFileLowering()); | ||
| TM->getObjFileLowering()->Initialize(*MCFoo, *TM); | ||
| MCFoo->setObjectFileInfo(TM->getObjFileLowering()); | ||
| } | ||
|
|
||
| LLVMContext Context; | ||
| std::unique_ptr<TargetMachine> TM; | ||
| std::unique_ptr<Module> M; | ||
|
|
||
| std::unique_ptr<MCContext> MC; | ||
| std::unique_ptr<MCContext> MCFoo; | ||
|
|
||
| Function *Foo; | ||
| std::unique_ptr<MachineFunction> MFFoo; | ||
| }; | ||
|
|
||
| TEST_F(X86MCInstLowerTest, moExternalSymbol_MCSYMBOL) { | ||
|
|
||
| MachineModuleInfoWrapperPass *MMIWP = | ||
| new MachineModuleInfoWrapperPass(TM.get(), &*MCFoo); | ||
|
|
||
| legacy::PassManager PassMgrF; | ||
| SmallString<1024> Buf; | ||
| llvm::raw_svector_ostream OS(Buf); | ||
| AsmPrinter *Printer = | ||
| addPassesToEmitFile(PassMgrF, OS, CodeGenFileType::AssemblyFile, MMIWP); | ||
| PassMgrF.run(*M); | ||
|
|
||
| // Check GOT MCSymbol is from Printer.OutContext. | ||
| MCSymbol *GOTPrinterPtr = | ||
| Printer->OutContext.lookupSymbol("_GLOBAL_OFFSET_TABLE_"); | ||
|
|
||
| // Check GOT MCSymbol is NOT from MachineFunction's MCContext. | ||
| MCSymbol *GOTMFCtxPtr = | ||
| MMIWP->getMMI().getMachineFunction(*Foo)->getContext().lookupSymbol( | ||
| "_GLOBAL_OFFSET_TABLE_"); | ||
|
|
||
| EXPECT_NE(GOTPrinterPtr, nullptr); | ||
| EXPECT_EQ(GOTMFCtxPtr, nullptr); | ||
| } | ||
|
|
||
| } // end namespace llvm | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. This is starting to make more sense, now. Normally, there's only one MCContext, but because you're doing this "parallel codegen" thing, you're passing a different MCContext to construct the MachineFunction... and the coupling between a symbol and its context is loose enough that you can pass a symbol from the wrong MCContext to the AsmPrinter, and sort of get away with it.
If preventing that is the goal, why not change X86MCInstLower::X86MCInstLower instead? Just change
Ctx(mf.getContext())toCtx(asmprinter.OutContext).That said, more generally, if you want everything to work reliably, you'll probably need to completely eliminate the MCContext reference from MachineFunction. Otherwise, you'll continue to run into issues where the MCSymbol is from the wrong context. Maybe doable, but involves a significant amount of refactoring to avoid constructing MCSymbols early... and I'm not sure if there are any other weird interactions here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, this probably won't work (I mean it will work for MO_ExternalSymbol to get a unique MCSymbol, but) because we do still need
mf.getContext()to do most of the codegen here for this function pass to run on the correspondingMachineFunction.Ctxhas to bemf.getContext()as most of the codegen for this MachineFunction is in this MCContext. AsmPrinter's OutContext is just for the output here.Yeah, for most cases,
AsmPrinter.OutContextis the same asmf.getContextbecause there is just oneMCContextin the whole pipeline. I'm not sure what is the motivation for other backends to also useAsmPrinter.OutContextfor the same case here, but the change does make them look more consistent with each other 😀There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting idea, but I do need to think more about what does this entails, and as you said, it will probably be a significant amount of refactoring, so maybe as follow-ups with more concrete considerations on a larger scale refactoring?
(Also very selfishly speaking, this PR will help significantly with our MCLinker to function correctly, otherwise, half of tests are failing now 😢, so would be great to get something in first so that we can keep upgrading weekly 🙏 . )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really understanding what this means... I guess you've sort of informally partitioned things so that "local" symbols are created in the function's MCContext, and "global" symbols are created in the global MCContext? I don't think that's really sustainable... if we're going to consistently partition symbols, the two kinds of symbols can't both just be
MCSymbol*, or you'll inevitably trip over issues in more obscure cases where we use the wrong MCContext.I don't think the patch in its current form will cause any immediate issues, but I don't want to commit to a design that hasn't really been reviewed by LLVM community, and probably won't be approved in its current form because it's very confusing.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is valid concern, but we are willing to take the risk for potentially running into issues (since we don't have substantial example right now to show this will be a big problem and worrying about "what-if-sm" is hard 😞) in the future at this point to unblock all of our tests. I'm definitely open to suggestion on how to make the MCLinker more solid (maybe after/during my talk next month?).
I understand your reservation and being careful, thank you for being thorough here! Though I want to point out that this change has already been applied to most of other backends (and I imagine those changes were being reviewed and approved by the community?). So I'd push back a bit on the assumption that this is "a design that hasn't really been reviewed by LLVM community"?
Do you have any suggestion on which part is confusing and what can be added to make it less so? 🙏
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't the two kinds be both "MCSymbo*" just because their scopes are different (local vs global)? What's wrong with `MCSymbo' wrt scoping? Also, I don't quite get "inevitably trip over issues in more obscure cases" part, I'm afraid it's a bit vague statement. Could you be more specific on what cases that may be? And since most of other backends are already doing this, do you think they are also doing something unsustainable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@efriedma-quic the absence of a fix blocks our pulldown as 50% of tests are failing due to reverted #133291 (comment) change.
Even though I agree that there might be a better "bulletproof" solution, but is it ok to move forward with Weiwei's fix first and then consider much better solution ? My rationale here is that Weiwei's proposed fix is aligned with what most of the targets are doing now and also there was an interest in community to open source parallel MCLinker. So when it comes to open sourcing there will be more use-cases and we will come back to that topic again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other backends work in your model by accident. They're not intentionally using one context or the other, they're just not using MachineFunction::getContext() at all in the AsmPrinter.
Basically, if MF.getContext().getOrCreateSymbol() means something different from AsmPrinter.OutContext.getOrCreateSymbol(), it's a lot harder to understand what's going on. You have two APIs that look the same on the surface, and return a value of the same type, but actually mean something subtly different. Anything that creates an MCSymbol would need to be aware that both APIs exist, and pick the correct one. Some existing code probably isn't consistent with your model, and anyone writing new code gets zero guidance from the API names or type system to help pick the correct one.
And the "local" one is never really right: MCSymbols passed to an MCStreamer are supposed to be part of the same MCContext as the MCStreamer.
To make things consistent, there needs to be one correct way to construct an MCSymbol. Either we need a "MachineFunctionSymbol" type to represent symbols that haven't been emitted yet, or you need to stop sharing MCStreamers between different compilation units. This patch isn't making any progress towards either of those models, or anything similar.
I don't think this patch will cause any immediate issues, because it's basically a no-op if there's only one MCContext, but this isn't the right long-term solution. And I don't want to commit to merging an unbounded number of temporary hacks while you work out how to implement the right solution.