Skip to content

[CodeGen] Fix MachineModuleInfo's move constructor to be more safe with MCContext ownership. #104834

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
6 changes: 3 additions & 3 deletions llvm/include/llvm/CodeGen/MachineModuleInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class MachineModuleInfo {
const LLVMTargetMachine &TM;

/// This is the MCContext used for the entire code generator.
MCContext Context;
std::unique_ptr<MCContext> Context;
// This is an external context, that if assigned, will be used instead of the
// internal context.
MCContext *ExternalContext = nullptr;
Expand Down Expand Up @@ -124,10 +124,10 @@ class MachineModuleInfo {
const LLVMTargetMachine &getTarget() const { return TM; }

const MCContext &getContext() const {
return ExternalContext ? *ExternalContext : Context;
return ExternalContext ? *ExternalContext : *Context;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we get rid of this ExternalContext business? I don't understand why it's here. If it's necessary to construct with an external context, I would expect that to be the only way to construct MMI

Copy link
Contributor Author

@weiweichen weiweichen Aug 19, 2024

Choose a reason for hiding this comment

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

Maybe? I don't understand why it's here either (and my PR is not doing anything with it 😛). Any chance we can decide the fate of ExternalContext in a separate PR since it's out of the scope of this one?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd say it's the same scope, for what should own the MCContext

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, it explicitly said This is an external context which means someone else is owning it instead of this here, so not quite the same scope, no?

Copy link
Contributor

Choose a reason for hiding this comment

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

The question that needs to be answered is "who owns the MCContext". I think the answer should be definitely MachineModuleInfo, or definitively an external owner. Having 2 modes here is a bad API

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree; See my comments below. IMO it's better to have an external owner. It will bring MMI closer to how llvm::Module is managed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Having 2 modes here is a bad API

I personally agree with this in principal, but again, I don't have much context on why these two are here originally, so I'd prefer not having to decide the fate of this API while not understanding the original intension of the design. If anyone else has more context, I'd really love to hear and happy to make another PR to improve this.

}
MCContext &getContext() {
return ExternalContext ? *ExternalContext : Context;
return ExternalContext ? *ExternalContext : *Context;
}

const Module *getModule() const { return TheModule; }
Expand Down
26 changes: 13 additions & 13 deletions llvm/lib/CodeGen/MachineModuleInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,39 @@ void MachineModuleInfo::initialize() {
}

void MachineModuleInfo::finalize() {
Context.reset();
if (Context)
Context->reset();
// We don't clear the ExternalContext.

delete ObjFileMMI;
ObjFileMMI = nullptr;
}

MachineModuleInfo::MachineModuleInfo(MachineModuleInfo &&MMI)
: TM(std::move(MMI.TM)),
Context(TM.getTargetTriple(), TM.getMCAsmInfo(), TM.getMCRegisterInfo(),
TM.getMCSubtargetInfo(), nullptr, &TM.Options.MCOptions, false),
: TM(std::move(MMI.TM)), Context(std::move(MMI.Context)),
MachineFunctions(std::move(MMI.MachineFunctions)) {
Context.setObjectFileInfo(TM.getObjFileLowering());
ObjFileMMI = MMI.ObjFileMMI;
ExternalContext = MMI.ExternalContext;
TheModule = MMI.TheModule;
}

MachineModuleInfo::MachineModuleInfo(const LLVMTargetMachine *TM)
: TM(*TM), Context(TM->getTargetTriple(), TM->getMCAsmInfo(),
TM->getMCRegisterInfo(), TM->getMCSubtargetInfo(),
nullptr, &TM->Options.MCOptions, false) {
Context.setObjectFileInfo(TM->getObjFileLowering());
: TM(*TM),
Context(std::make_unique<MCContext>(
TM->getTargetTriple(), TM->getMCAsmInfo(), TM->getMCRegisterInfo(),
TM->getMCSubtargetInfo(), nullptr, &TM->Options.MCOptions, false)) {
Context->setObjectFileInfo(TM->getObjFileLowering());
initialize();
}

MachineModuleInfo::MachineModuleInfo(const LLVMTargetMachine *TM,
MCContext *ExtContext)
: TM(*TM), Context(TM->getTargetTriple(), TM->getMCAsmInfo(),
TM->getMCRegisterInfo(), TM->getMCSubtargetInfo(),
nullptr, &TM->Options.MCOptions, false),
: TM(*TM),
Context(std::make_unique<MCContext>(
TM->getTargetTriple(), TM->getMCAsmInfo(), TM->getMCRegisterInfo(),
TM->getMCSubtargetInfo(), nullptr, &TM->Options.MCOptions, false)),
ExternalContext(ExtContext) {
Context.setObjectFileInfo(TM->getObjFileLowering());
Context->setObjectFileInfo(TM->getObjFileLowering());
initialize();
}

Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ add_llvm_unittest(CodeGenTests
MachineDomTreeUpdaterTest.cpp
MachineInstrBundleIteratorTest.cpp
MachineInstrTest.cpp
MachineModuleInfoTest.cpp
MachineOperandTest.cpp
RegAllocScoreTest.cpp
PassManagerTest.cpp
Expand Down
79 changes: 79 additions & 0 deletions llvm/unittests/CodeGen/MachineModuleInfoTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===- llvm/unittest/CodeGen/PassManager.cpp - PassManager tests ----------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// Test MachineModuleInfo.
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/TargetParser/Host.h"
#include "gtest/gtest.h"

using namespace llvm;

namespace {

std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) {
SMDiagnostic Err;
return parseAssemblyString(IR, Err, Context);
}

class MachineModuleInfoTest : public ::testing::Test {
protected:
LLVMContext Context;
std::unique_ptr<Module> M;
std::unique_ptr<TargetMachine> TM;

public:
MachineModuleInfoTest()
: M(parseIR(Context, "define void @f() {\n"
"entry:\n"
" call void @g()\n"
" ret void\n"
"}\n"
"define void @g() {\n"
" ret void\n"
"}\n")) {
// MachineModuleInfo needs a TargetMachine instance.
llvm::InitializeAllTargets();

std::string TripleName = Triple::normalize(sys::getDefaultTargetTriple());
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
if (!TheTarget)
return;

TargetOptions Options;
TM.reset(TheTarget->createTargetMachine(TripleName, "", "", Options,
std::nullopt));
}
};

TEST_F(MachineModuleInfoTest, MachineModuleInfoMoveConstructorMovesMCContext) {
if (!TM)
GTEST_SKIP();

LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());
M->setDataLayout(TM->createDataLayout());

MachineModuleInfo MMI(LLVMTM);

MCContext *OriginalCtx = &MMI.getContext();

MachineModuleInfo MovedMMI(std::move(MMI));
MCContext *MovedCtx = &MovedMMI.getContext();

EXPECT_EQ(OriginalCtx, MovedCtx);
}

} // end namespace
Loading