1 //===-- llvm/CodeGen/GlobalISel/Legalizer.cpp -----------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 /// \file This file implements the LegalizerHelper class to legalize individual
10 /// instructions and the LegalizePass wrapper pass for the primary
13 //===----------------------------------------------------------------------===//
15 #include "llvm/CodeGen/GlobalISel/Legalizer.h"
16 #include "llvm/ADT/PostOrderIterator.h"
17 #include "llvm/ADT/SetVector.h"
18 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
19 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
20 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
21 #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
22 #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
23 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
24 #include "llvm/CodeGen/GlobalISel/Utils.h"
25 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
26 #include "llvm/CodeGen/MachineRegisterInfo.h"
27 #include "llvm/CodeGen/TargetPassConfig.h"
28 #include "llvm/CodeGen/TargetSubtargetInfo.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Target/TargetMachine.h"
34 #define DEBUG_TYPE "legalizer"
39 EnableCSEInLegalizer("enable-cse-in-legalizer",
40 cl::desc("Should enable CSE in Legalizer"),
41 cl::Optional
, cl::init(false));
43 char Legalizer::ID
= 0;
44 INITIALIZE_PASS_BEGIN(Legalizer
, DEBUG_TYPE
,
45 "Legalize the Machine IR a function's Machine IR", false,
47 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig
)
48 INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass
)
49 INITIALIZE_PASS_END(Legalizer
, DEBUG_TYPE
,
50 "Legalize the Machine IR a function's Machine IR", false,
53 Legalizer::Legalizer() : MachineFunctionPass(ID
) {
54 initializeLegalizerPass(*PassRegistry::getPassRegistry());
57 void Legalizer::getAnalysisUsage(AnalysisUsage
&AU
) const {
58 AU
.addRequired
<TargetPassConfig
>();
59 AU
.addRequired
<GISelCSEAnalysisWrapperPass
>();
60 AU
.addPreserved
<GISelCSEAnalysisWrapperPass
>();
61 getSelectionDAGFallbackAnalysisUsage(AU
);
62 MachineFunctionPass::getAnalysisUsage(AU
);
65 void Legalizer::init(MachineFunction
&MF
) {
68 static bool isArtifact(const MachineInstr
&MI
) {
69 switch (MI
.getOpcode()) {
72 case TargetOpcode::G_TRUNC
:
73 case TargetOpcode::G_ZEXT
:
74 case TargetOpcode::G_ANYEXT
:
75 case TargetOpcode::G_SEXT
:
76 case TargetOpcode::G_MERGE_VALUES
:
77 case TargetOpcode::G_UNMERGE_VALUES
:
78 case TargetOpcode::G_CONCAT_VECTORS
:
79 case TargetOpcode::G_BUILD_VECTOR
:
80 case TargetOpcode::G_EXTRACT
:
84 using InstListTy
= GISelWorkList
<256>;
85 using ArtifactListTy
= GISelWorkList
<128>;
88 class LegalizerWorkListManager
: public GISelChangeObserver
{
90 ArtifactListTy
&ArtifactList
;
92 SmallVector
<MachineInstr
*, 4> NewMIs
;
96 LegalizerWorkListManager(InstListTy
&Insts
, ArtifactListTy
&Arts
)
97 : InstList(Insts
), ArtifactList(Arts
) {}
99 void createdOrChangedInstr(MachineInstr
&MI
) {
100 // Only legalize pre-isel generic instructions.
101 // Legalization process could generate Target specific pseudo
102 // instructions with generic types. Don't record them
103 if (isPreISelGenericOpcode(MI
.getOpcode())) {
105 ArtifactList
.insert(&MI
);
107 InstList
.insert(&MI
);
111 void createdInstr(MachineInstr
&MI
) override
{
112 LLVM_DEBUG(dbgs() << ".. .. New MI: " << MI
);
113 LLVM_DEBUG(NewMIs
.push_back(&MI
));
114 createdOrChangedInstr(MI
);
117 void printNewInstrs() {
119 for (const auto *MI
: NewMIs
)
120 dbgs() << ".. .. New MI: " << *MI
;
125 void erasingInstr(MachineInstr
&MI
) override
{
126 LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI
);
127 InstList
.remove(&MI
);
128 ArtifactList
.remove(&MI
);
131 void changingInstr(MachineInstr
&MI
) override
{
132 LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI
);
135 void changedInstr(MachineInstr
&MI
) override
{
136 // When insts change, we want to revisit them to legalize them again.
137 // We'll consider them the same as created.
138 LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI
);
139 createdOrChangedInstr(MI
);
144 bool Legalizer::runOnMachineFunction(MachineFunction
&MF
) {
145 // If the ISel pipeline failed, do not bother running that pass.
146 if (MF
.getProperties().hasProperty(
147 MachineFunctionProperties::Property::FailedISel
))
149 LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF
.getName() << '\n');
151 const TargetPassConfig
&TPC
= getAnalysis
<TargetPassConfig
>();
152 GISelCSEAnalysisWrapper
&Wrapper
=
153 getAnalysis
<GISelCSEAnalysisWrapperPass
>().getCSEWrapper();
154 MachineOptimizationRemarkEmitter
MORE(MF
, /*MBFI=*/nullptr);
156 const size_t NumBlocks
= MF
.size();
157 MachineRegisterInfo
&MRI
= MF
.getRegInfo();
161 ArtifactListTy ArtifactList
;
162 ReversePostOrderTraversal
<MachineFunction
*> RPOT(&MF
);
163 // Perform legalization bottom up so we can DCE as we legalize.
164 // Traverse BB in RPOT and within each basic block, add insts top down,
165 // so when we pop_back_val in the legalization process, we traverse bottom-up.
166 for (auto *MBB
: RPOT
) {
169 for (MachineInstr
&MI
: *MBB
) {
170 // Only legalize pre-isel generic instructions: others don't have types
171 // and are assumed to be legal.
172 if (!isPreISelGenericOpcode(MI
.getOpcode()))
175 ArtifactList
.deferred_insert(&MI
);
177 InstList
.deferred_insert(&MI
);
180 ArtifactList
.finalize();
182 std::unique_ptr
<MachineIRBuilder
> MIRBuilder
;
183 GISelCSEInfo
*CSEInfo
= nullptr;
184 bool EnableCSE
= EnableCSEInLegalizer
.getNumOccurrences()
185 ? EnableCSEInLegalizer
186 : TPC
.isGISelCSEEnabled();
189 MIRBuilder
= make_unique
<CSEMIRBuilder
>();
190 CSEInfo
= &Wrapper
.get(TPC
.getCSEConfig());
191 MIRBuilder
->setCSEInfo(CSEInfo
);
193 MIRBuilder
= make_unique
<MachineIRBuilder
>();
194 // This observer keeps the worklist updated.
195 LegalizerWorkListManager
WorkListObserver(InstList
, ArtifactList
);
196 // We want both WorkListObserver as well as CSEInfo to observe all changes.
197 // Use the wrapper observer.
198 GISelObserverWrapper
WrapperObserver(&WorkListObserver
);
199 if (EnableCSE
&& CSEInfo
)
200 WrapperObserver
.addObserver(CSEInfo
);
201 // Now install the observer as the delegate to MF.
202 // This will keep all the observers notified about new insertions/deletions.
203 RAIIDelegateInstaller
DelInstall(MF
, &WrapperObserver
);
204 LegalizerHelper
Helper(MF
, WrapperObserver
, *MIRBuilder
.get());
205 const LegalizerInfo
&LInfo(Helper
.getLegalizerInfo());
206 LegalizationArtifactCombiner
ArtCombiner(*MIRBuilder
.get(), MF
.getRegInfo(),
208 auto RemoveDeadInstFromLists
= [&WrapperObserver
](MachineInstr
*DeadMI
) {
209 WrapperObserver
.erasingInstr(*DeadMI
);
211 bool Changed
= false;
213 while (!InstList
.empty()) {
214 MachineInstr
&MI
= *InstList
.pop_back_val();
215 assert(isPreISelGenericOpcode(MI
.getOpcode()) && "Expecting generic opcode");
216 if (isTriviallyDead(MI
, MRI
)) {
217 LLVM_DEBUG(dbgs() << MI
<< "Is dead; erasing.\n");
218 MI
.eraseFromParentAndMarkDBGValuesForRemoval();
222 // Do the legalization for this instruction.
223 auto Res
= Helper
.legalizeInstrStep(MI
);
224 // Error out if we couldn't legalize this instruction. We may want to
225 // fall back to DAG ISel instead in the future.
226 if (Res
== LegalizerHelper::UnableToLegalize
) {
227 Helper
.MIRBuilder
.stopObservingChanges();
228 reportGISelFailure(MF
, TPC
, MORE
, "gisel-legalize",
229 "unable to legalize instruction", MI
);
232 WorkListObserver
.printNewInstrs();
233 Changed
|= Res
== LegalizerHelper::Legalized
;
235 while (!ArtifactList
.empty()) {
236 MachineInstr
&MI
= *ArtifactList
.pop_back_val();
237 assert(isPreISelGenericOpcode(MI
.getOpcode()) && "Expecting generic opcode");
238 if (isTriviallyDead(MI
, MRI
)) {
239 LLVM_DEBUG(dbgs() << MI
<< "Is dead\n");
240 RemoveDeadInstFromLists(&MI
);
241 MI
.eraseFromParentAndMarkDBGValuesForRemoval();
244 SmallVector
<MachineInstr
*, 4> DeadInstructions
;
245 if (ArtCombiner
.tryCombineInstruction(MI
, DeadInstructions
,
247 WorkListObserver
.printNewInstrs();
248 for (auto *DeadMI
: DeadInstructions
) {
249 LLVM_DEBUG(dbgs() << *DeadMI
<< "Is dead\n");
250 RemoveDeadInstFromLists(DeadMI
);
251 DeadMI
->eraseFromParentAndMarkDBGValuesForRemoval();
256 // If this was not an artifact (that could be combined away), this might
257 // need special handling. Add it to InstList, so when it's processed
258 // there, it has to be legal or specially handled.
260 InstList
.insert(&MI
);
262 } while (!InstList
.empty());
264 // For now don't support if new blocks are inserted - we would need to fix the
265 // outerloop for that.
266 if (MF
.size() != NumBlocks
) {
267 MachineOptimizationRemarkMissed
R("gisel-legalize", "GISelFailure",
268 MF
.getFunction().getSubprogram(),
270 R
<< "inserting blocks is not supported yet";
271 reportGISelFailure(MF
, TPC
, MORE
, R
);