Bug Summary

File:llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
Warning:line 397, column 60
Division by zero

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Legalizer.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/build-llvm -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I lib/CodeGen/GlobalISel -I /build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel -I include -I /build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-command-line-argument -Wno-unknown-warning-option -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/build-llvm -ferror-limit 19 -fvisibility-inlines-hidden -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-10-17-004846-21170-1 -x c++ /build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp

/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp

1//===-- llvm/CodeGen/GlobalISel/Legalizer.cpp -----------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file This file implements the LegalizerHelper class to legalize individual
10/// instructions and the LegalizePass wrapper pass for the primary
11/// legalization.
12//
13//===----------------------------------------------------------------------===//
14
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/LostDebugLocObserver.h"
25#include "llvm/CodeGen/GlobalISel/Utils.h"
26#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
27#include "llvm/CodeGen/MachineRegisterInfo.h"
28#include "llvm/CodeGen/TargetPassConfig.h"
29#include "llvm/CodeGen/TargetSubtargetInfo.h"
30#include "llvm/InitializePasses.h"
31#include "llvm/Support/Debug.h"
32#include "llvm/Support/Error.h"
33#include "llvm/Target/TargetMachine.h"
34
35#include <iterator>
36
37#define DEBUG_TYPE"legalizer" "legalizer"
38
39using namespace llvm;
40
41static cl::opt<bool>
42 EnableCSEInLegalizer("enable-cse-in-legalizer",
43 cl::desc("Should enable CSE in Legalizer"),
44 cl::Optional, cl::init(false));
45
46// This is a temporary hack, should be removed soon.
47static cl::opt<bool> AllowGInsertAsArtifact(
48 "allow-ginsert-as-artifact",
49 cl::desc("Allow G_INSERT to be considered an artifact. Hack around AMDGPU "
50 "test infinite loops."),
51 cl::Optional, cl::init(true));
52
53enum class DebugLocVerifyLevel {
54 None,
55 Legalizations,
56 LegalizationsAndArtifactCombiners,
57};
58#ifndef NDEBUG
59static cl::opt<DebugLocVerifyLevel> VerifyDebugLocs(
60 "verify-legalizer-debug-locs",
61 cl::desc("Verify that debug locations are handled"),
62 cl::values(
63 clEnumValN(DebugLocVerifyLevel::None, "none", "No verification")llvm::cl::OptionEnumValue { "none", int(DebugLocVerifyLevel::
None), "No verification" }
,
64 clEnumValN(DebugLocVerifyLevel::Legalizations, "legalizations",llvm::cl::OptionEnumValue { "legalizations", int(DebugLocVerifyLevel
::Legalizations), "Verify legalizations" }
65 "Verify legalizations")llvm::cl::OptionEnumValue { "legalizations", int(DebugLocVerifyLevel
::Legalizations), "Verify legalizations" }
,
66 clEnumValN(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners,llvm::cl::OptionEnumValue { "legalizations+artifactcombiners"
, int(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners)
, "Verify legalizations and artifact combines" }
67 "legalizations+artifactcombiners",llvm::cl::OptionEnumValue { "legalizations+artifactcombiners"
, int(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners)
, "Verify legalizations and artifact combines" }
68 "Verify legalizations and artifact combines")llvm::cl::OptionEnumValue { "legalizations+artifactcombiners"
, int(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners)
, "Verify legalizations and artifact combines" }
),
69 cl::init(DebugLocVerifyLevel::Legalizations));
70#else
71// Always disable it for release builds by preventing the observer from being
72// installed.
73static const DebugLocVerifyLevel VerifyDebugLocs = DebugLocVerifyLevel::None;
74#endif
75
76char Legalizer::ID = 0;
77INITIALIZE_PASS_BEGIN(Legalizer, DEBUG_TYPE,static void *initializeLegalizerPassOnce(PassRegistry &Registry
) {
78 "Legalize the Machine IR a function's Machine IR", false,static void *initializeLegalizerPassOnce(PassRegistry &Registry
) {
79 false)static void *initializeLegalizerPassOnce(PassRegistry &Registry
) {
80INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)initializeTargetPassConfigPass(Registry);
81INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)initializeGISelCSEAnalysisWrapperPassPass(Registry);
82INITIALIZE_PASS_END(Legalizer, DEBUG_TYPE,PassInfo *PI = new PassInfo( "Legalize the Machine IR a function's Machine IR"
, "legalizer", &Legalizer::ID, PassInfo::NormalCtor_t(callDefaultCtor
<Legalizer>), false, false); Registry.registerPass(*PI,
true); return PI; } static llvm::once_flag InitializeLegalizerPassFlag
; void llvm::initializeLegalizerPass(PassRegistry &Registry
) { llvm::call_once(InitializeLegalizerPassFlag, initializeLegalizerPassOnce
, std::ref(Registry)); }
83 "Legalize the Machine IR a function's Machine IR", false,PassInfo *PI = new PassInfo( "Legalize the Machine IR a function's Machine IR"
, "legalizer", &Legalizer::ID, PassInfo::NormalCtor_t(callDefaultCtor
<Legalizer>), false, false); Registry.registerPass(*PI,
true); return PI; } static llvm::once_flag InitializeLegalizerPassFlag
; void llvm::initializeLegalizerPass(PassRegistry &Registry
) { llvm::call_once(InitializeLegalizerPassFlag, initializeLegalizerPassOnce
, std::ref(Registry)); }
84 false)PassInfo *PI = new PassInfo( "Legalize the Machine IR a function's Machine IR"
, "legalizer", &Legalizer::ID, PassInfo::NormalCtor_t(callDefaultCtor
<Legalizer>), false, false); Registry.registerPass(*PI,
true); return PI; } static llvm::once_flag InitializeLegalizerPassFlag
; void llvm::initializeLegalizerPass(PassRegistry &Registry
) { llvm::call_once(InitializeLegalizerPassFlag, initializeLegalizerPassOnce
, std::ref(Registry)); }
85
86Legalizer::Legalizer() : MachineFunctionPass(ID) { }
87
88void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const {
89 AU.addRequired<TargetPassConfig>();
90 AU.addRequired<GISelCSEAnalysisWrapperPass>();
91 AU.addPreserved<GISelCSEAnalysisWrapperPass>();
92 getSelectionDAGFallbackAnalysisUsage(AU);
93 MachineFunctionPass::getAnalysisUsage(AU);
94}
95
96void Legalizer::init(MachineFunction &MF) {
97}
98
99static bool isArtifact(const MachineInstr &MI) {
100 switch (MI.getOpcode()) {
101 default:
102 return false;
103 case TargetOpcode::G_TRUNC:
104 case TargetOpcode::G_ZEXT:
105 case TargetOpcode::G_ANYEXT:
106 case TargetOpcode::G_SEXT:
107 case TargetOpcode::G_MERGE_VALUES:
108 case TargetOpcode::G_UNMERGE_VALUES:
109 case TargetOpcode::G_CONCAT_VECTORS:
110 case TargetOpcode::G_BUILD_VECTOR:
111 case TargetOpcode::G_EXTRACT:
112 return true;
113 case TargetOpcode::G_INSERT:
114 return AllowGInsertAsArtifact;
115 }
116}
117using InstListTy = GISelWorkList<256>;
118using ArtifactListTy = GISelWorkList<128>;
119
120namespace {
121class LegalizerWorkListManager : public GISelChangeObserver {
122 InstListTy &InstList;
123 ArtifactListTy &ArtifactList;
124#ifndef NDEBUG
125 SmallVector<MachineInstr *, 4> NewMIs;
126#endif
127
128public:
129 LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts)
130 : InstList(Insts), ArtifactList(Arts) {}
131
132 void createdOrChangedInstr(MachineInstr &MI) {
133 // Only legalize pre-isel generic instructions.
134 // Legalization process could generate Target specific pseudo
135 // instructions with generic types. Don't record them
136 if (isPreISelGenericOpcode(MI.getOpcode())) {
137 if (isArtifact(MI))
138 ArtifactList.insert(&MI);
139 else
140 InstList.insert(&MI);
141 }
142 }
143
144 void createdInstr(MachineInstr &MI) override {
145 LLVM_DEBUG(NewMIs.push_back(&MI))do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { NewMIs.push_back(&MI); } } while (false)
;
146 createdOrChangedInstr(MI);
147 }
148
149 void printNewInstrs() {
150 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { { for (const auto *MI : NewMIs) dbgs() <<
".. .. New MI: " << *MI; NewMIs.clear(); }; } } while (
false)
151 for (const auto *MI : NewMIs)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { { for (const auto *MI : NewMIs) dbgs() <<
".. .. New MI: " << *MI; NewMIs.clear(); }; } } while (
false)
152 dbgs() << ".. .. New MI: " << *MI;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { { for (const auto *MI : NewMIs) dbgs() <<
".. .. New MI: " << *MI; NewMIs.clear(); }; } } while (
false)
153 NewMIs.clear();do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { { for (const auto *MI : NewMIs) dbgs() <<
".. .. New MI: " << *MI; NewMIs.clear(); }; } } while (
false)
154 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { { for (const auto *MI : NewMIs) dbgs() <<
".. .. New MI: " << *MI; NewMIs.clear(); }; } } while (
false)
;
155 }
156
157 void erasingInstr(MachineInstr &MI) override {
158 LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. .. Erasing: " << MI
; } } while (false)
;
159 InstList.remove(&MI);
160 ArtifactList.remove(&MI);
161 }
162
163 void changingInstr(MachineInstr &MI) override {
164 LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. .. Changing MI: " <<
MI; } } while (false)
;
165 }
166
167 void changedInstr(MachineInstr &MI) override {
168 // When insts change, we want to revisit them to legalize them again.
169 // We'll consider them the same as created.
170 LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. .. Changed MI: " <<
MI; } } while (false)
;
171 createdOrChangedInstr(MI);
172 }
173};
174} // namespace
175
176Legalizer::MFResult
177Legalizer::legalizeMachineFunction(MachineFunction &MF, const LegalizerInfo &LI,
178 ArrayRef<GISelChangeObserver *> AuxObservers,
179 LostDebugLocObserver &LocObserver,
180 MachineIRBuilder &MIRBuilder) {
181 MIRBuilder.setMF(MF);
182 MachineRegisterInfo &MRI = MF.getRegInfo();
183
184 // Populate worklists.
185 InstListTy InstList;
186 ArtifactListTy ArtifactList;
187 ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
188 // Perform legalization bottom up so we can DCE as we legalize.
189 // Traverse BB in RPOT and within each basic block, add insts top down,
190 // so when we pop_back_val in the legalization process, we traverse bottom-up.
191 for (auto *MBB : RPOT) {
192 if (MBB->empty())
193 continue;
194 for (MachineInstr &MI : *MBB) {
195 // Only legalize pre-isel generic instructions: others don't have types
196 // and are assumed to be legal.
197 if (!isPreISelGenericOpcode(MI.getOpcode()))
198 continue;
199 if (isArtifact(MI))
200 ArtifactList.deferred_insert(&MI);
201 else
202 InstList.deferred_insert(&MI);
203 }
204 }
205 ArtifactList.finalize();
206 InstList.finalize();
207
208 // This observer keeps the worklists updated.
209 LegalizerWorkListManager WorkListObserver(InstList, ArtifactList);
210 // We want both WorkListObserver as well as all the auxiliary observers (e.g.
211 // CSEInfo) to observe all changes. Use the wrapper observer.
212 GISelObserverWrapper WrapperObserver(&WorkListObserver);
213 for (GISelChangeObserver *Observer : AuxObservers)
12
Assuming '__begin1' is equal to '__end1'
214 WrapperObserver.addObserver(Observer);
215
216 // Now install the observer as the delegate to MF.
217 // This will keep all the observers notified about new insertions/deletions.
218 RAIIMFObsDelInstaller Installer(MF, WrapperObserver);
219 LegalizerHelper Helper(MF, LI, WrapperObserver, MIRBuilder);
220 LegalizationArtifactCombiner ArtCombiner(MIRBuilder, MRI, LI);
221 bool Changed = false;
222 SmallVector<MachineInstr *, 128> RetryList;
223 do {
224 LLVM_DEBUG(dbgs() << "=== New Iteration ===\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "=== New Iteration ===\n"; }
} while (false)
;
13
Assuming 'DebugFlag' is false
225 assert(RetryList.empty() && "Expected no instructions in RetryList")(static_cast <bool> (RetryList.empty() && "Expected no instructions in RetryList"
) ? void (0) : __assert_fail ("RetryList.empty() && \"Expected no instructions in RetryList\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 225, __extension__ __PRETTY_FUNCTION__))
;
14
Loop condition is false. Exiting loop
15
'?' condition is true
226 unsigned NumArtifacts = ArtifactList.size();
227 while (!InstList.empty()) {
16
Assuming the condition is false
17
Loop condition is false. Execution continues on line 263
228 MachineInstr &MI = *InstList.pop_back_val();
229 assert(isPreISelGenericOpcode(MI.getOpcode()) &&(static_cast <bool> (isPreISelGenericOpcode(MI.getOpcode
()) && "Expecting generic opcode") ? void (0) : __assert_fail
("isPreISelGenericOpcode(MI.getOpcode()) && \"Expecting generic opcode\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 230, __extension__ __PRETTY_FUNCTION__))
230 "Expecting generic opcode")(static_cast <bool> (isPreISelGenericOpcode(MI.getOpcode
()) && "Expecting generic opcode") ? void (0) : __assert_fail
("isPreISelGenericOpcode(MI.getOpcode()) && \"Expecting generic opcode\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 230, __extension__ __PRETTY_FUNCTION__))
;
231 if (isTriviallyDead(MI, MRI)) {
232 eraseInstr(MI, MRI, &LocObserver);
233 continue;
234 }
235
236 // Do the legalization for this instruction.
237 auto Res = Helper.legalizeInstrStep(MI, LocObserver);
238 // Error out if we couldn't legalize this instruction. We may want to
239 // fall back to DAG ISel instead in the future.
240 if (Res == LegalizerHelper::UnableToLegalize) {
241 // Move illegal artifacts to RetryList instead of aborting because
242 // legalizing InstList may generate artifacts that allow
243 // ArtifactCombiner to combine away them.
244 if (isArtifact(MI)) {
245 LLVM_DEBUG(dbgs() << ".. Not legalized, moving to artifacts retry\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Not legalized, moving to artifacts retry\n"
; } } while (false)
;
246 assert(NumArtifacts == 0 &&(static_cast <bool> (NumArtifacts == 0 && "Artifacts are only expected in instruction list starting the "
"second iteration, but each iteration starting second must "
"start with an empty artifacts list") ? void (0) : __assert_fail
("NumArtifacts == 0 && \"Artifacts are only expected in instruction list starting the \" \"second iteration, but each iteration starting second must \" \"start with an empty artifacts list\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 249, __extension__ __PRETTY_FUNCTION__))
247 "Artifacts are only expected in instruction list starting the "(static_cast <bool> (NumArtifacts == 0 && "Artifacts are only expected in instruction list starting the "
"second iteration, but each iteration starting second must "
"start with an empty artifacts list") ? void (0) : __assert_fail
("NumArtifacts == 0 && \"Artifacts are only expected in instruction list starting the \" \"second iteration, but each iteration starting second must \" \"start with an empty artifacts list\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 249, __extension__ __PRETTY_FUNCTION__))
248 "second iteration, but each iteration starting second must "(static_cast <bool> (NumArtifacts == 0 && "Artifacts are only expected in instruction list starting the "
"second iteration, but each iteration starting second must "
"start with an empty artifacts list") ? void (0) : __assert_fail
("NumArtifacts == 0 && \"Artifacts are only expected in instruction list starting the \" \"second iteration, but each iteration starting second must \" \"start with an empty artifacts list\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 249, __extension__ __PRETTY_FUNCTION__))
249 "start with an empty artifacts list")(static_cast <bool> (NumArtifacts == 0 && "Artifacts are only expected in instruction list starting the "
"second iteration, but each iteration starting second must "
"start with an empty artifacts list") ? void (0) : __assert_fail
("NumArtifacts == 0 && \"Artifacts are only expected in instruction list starting the \" \"second iteration, but each iteration starting second must \" \"start with an empty artifacts list\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 249, __extension__ __PRETTY_FUNCTION__))
;
250 (void)NumArtifacts;
251 RetryList.push_back(&MI);
252 continue;
253 }
254 Helper.MIRBuilder.stopObservingChanges();
255 return {Changed, &MI};
256 }
257 WorkListObserver.printNewInstrs();
258 LocObserver.checkpoint();
259 Changed |= Res == LegalizerHelper::Legalized;
260 }
261 // Try to combine the instructions in RetryList again if there
262 // are new artifacts. If not, stop legalizing.
263 if (!RetryList.empty()) {
18
Taking false branch
264 if (!ArtifactList.empty()) {
265 while (!RetryList.empty())
266 ArtifactList.insert(RetryList.pop_back_val());
267 } else {
268 LLVM_DEBUG(dbgs() << "No new artifacts created, not retrying!\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "No new artifacts created, not retrying!\n"
; } } while (false)
;
269 Helper.MIRBuilder.stopObservingChanges();
270 return {Changed, RetryList.front()};
271 }
272 }
273 LocObserver.checkpoint();
274 while (!ArtifactList.empty()) {
19
Assuming the condition is true
20
Loop condition is true. Entering loop body
275 MachineInstr &MI = *ArtifactList.pop_back_val();
276 assert(isPreISelGenericOpcode(MI.getOpcode()) &&(static_cast <bool> (isPreISelGenericOpcode(MI.getOpcode
()) && "Expecting generic opcode") ? void (0) : __assert_fail
("isPreISelGenericOpcode(MI.getOpcode()) && \"Expecting generic opcode\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 277, __extension__ __PRETTY_FUNCTION__))
21
'?' condition is true
277 "Expecting generic opcode")(static_cast <bool> (isPreISelGenericOpcode(MI.getOpcode
()) && "Expecting generic opcode") ? void (0) : __assert_fail
("isPreISelGenericOpcode(MI.getOpcode()) && \"Expecting generic opcode\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 277, __extension__ __PRETTY_FUNCTION__))
;
278 if (isTriviallyDead(MI, MRI)) {
22
Assuming the condition is false
23
Taking false branch
279 eraseInstr(MI, MRI, &LocObserver);
280 continue;
281 }
282 SmallVector<MachineInstr *, 4> DeadInstructions;
283 LLVM_DEBUG(dbgs() << "Trying to combine: " << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Trying to combine: " <<
MI; } } while (false)
;
24
Assuming 'DebugFlag' is false
25
Loop condition is false. Exiting loop
284 if (ArtCombiner.tryCombineInstruction(MI, DeadInstructions,
26
Calling 'LegalizationArtifactCombiner::tryCombineInstruction'
285 WrapperObserver)) {
286 WorkListObserver.printNewInstrs();
287 eraseInstrs(DeadInstructions, MRI, &LocObserver);
288 LocObserver.checkpoint(
289 VerifyDebugLocs ==
290 DebugLocVerifyLevel::LegalizationsAndArtifactCombiners);
291 Changed = true;
292 continue;
293 }
294 // If this was not an artifact (that could be combined away), this might
295 // need special handling. Add it to InstList, so when it's processed
296 // there, it has to be legal or specially handled.
297 else {
298 LLVM_DEBUG(dbgs() << ".. Not combined, moving to instructions list\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Not combined, moving to instructions list\n"
; } } while (false)
;
299 InstList.insert(&MI);
300 }
301 }
302 } while (!InstList.empty());
303
304 return {Changed, /*FailedOn*/ nullptr};
305}
306
307bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
308 // If the ISel pipeline failed, do not bother running that pass.
309 if (MF.getProperties().hasProperty(
310 MachineFunctionProperties::Property::FailedISel))
311 return false;
312 LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Legalize Machine IR for: " <<
MF.getName() << '\n'; } } while (false)
;
1
Taking false branch
2
Assuming 'DebugFlag' is false
3
Loop condition is false. Exiting loop
313 init(MF);
314 const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
315 GISelCSEAnalysisWrapper &Wrapper =
316 getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
317 MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
318
319 const size_t NumBlocks = MF.size();
320
321 std::unique_ptr<MachineIRBuilder> MIRBuilder;
322 GISelCSEInfo *CSEInfo = nullptr;
323 bool EnableCSE = EnableCSEInLegalizer.getNumOccurrences()
4
Assuming the condition is false
5
'?' condition is false
324 ? EnableCSEInLegalizer
325 : TPC.isGISelCSEEnabled();
326 if (EnableCSE) {
6
Assuming 'EnableCSE' is false
7
Taking false branch
327 MIRBuilder = std::make_unique<CSEMIRBuilder>();
328 CSEInfo = &Wrapper.get(TPC.getCSEConfig());
329 MIRBuilder->setCSEInfo(CSEInfo);
330 } else
331 MIRBuilder = std::make_unique<MachineIRBuilder>();
332
333 SmallVector<GISelChangeObserver *, 1> AuxObservers;
334 if (EnableCSE
7.1
'EnableCSE' is false
7.1
'EnableCSE' is false
&& CSEInfo) {
335 // We want CSEInfo in addition to WorkListObserver to observe all changes.
336 AuxObservers.push_back(CSEInfo);
337 }
338 assert(!CSEInfo || !errorToBool(CSEInfo->verify()))(static_cast <bool> (!CSEInfo || !errorToBool(CSEInfo->
verify())) ? void (0) : __assert_fail ("!CSEInfo || !errorToBool(CSEInfo->verify())"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp"
, 338, __extension__ __PRETTY_FUNCTION__))
;
8
'?' condition is true
339 LostDebugLocObserver LocObserver(DEBUG_TYPE"legalizer");
340 if (VerifyDebugLocs > DebugLocVerifyLevel::None)
9
Assuming the condition is false
10
Taking false branch
341 AuxObservers.push_back(&LocObserver);
342
343 const LegalizerInfo &LI = *MF.getSubtarget().getLegalizerInfo();
344 MFResult Result =
345 legalizeMachineFunction(MF, LI, AuxObservers, LocObserver, *MIRBuilder);
11
Calling 'Legalizer::legalizeMachineFunction'
346
347 if (Result.FailedOn) {
348 reportGISelFailure(MF, TPC, MORE, "gisel-legalize",
349 "unable to legalize instruction", *Result.FailedOn);
350 return false;
351 }
352 // For now don't support if new blocks are inserted - we would need to fix the
353 // outer loop for that.
354 if (MF.size() != NumBlocks) {
355 MachineOptimizationRemarkMissed R("gisel-legalize", "GISelFailure",
356 MF.getFunction().getSubprogram(),
357 /*MBB=*/nullptr);
358 R << "inserting blocks is not supported yet";
359 reportGISelFailure(MF, TPC, MORE, R);
360 return false;
361 }
362
363 if (LocObserver.getNumLostDebugLocs()) {
364 MachineOptimizationRemarkMissed R("gisel-legalize", "LostDebugLoc",
365 MF.getFunction().getSubprogram(),
366 /*MBB=*/&*MF.begin());
367 R << "lost "
368 << ore::NV("NumLostDebugLocs", LocObserver.getNumLostDebugLocs())
369 << " debug locations during pass";
370 reportGISelWarning(MF, TPC, MORE, R);
371 // Example remark:
372 // --- !Missed
373 // Pass: gisel-legalize
374 // Name: GISelFailure
375 // DebugLoc: { File: '.../legalize-urem.mir', Line: 1, Column: 0 }
376 // Function: test_urem_s32
377 // Args:
378 // - String: 'lost '
379 // - NumLostDebugLocs: '1'
380 // - String: ' debug locations during pass'
381 // ...
382 }
383
384 // If for some reason CSE was not enabled, make sure that we invalidate the
385 // CSEInfo object (as we currently declare that the analysis is preserved).
386 // The next time get on the wrapper is called, it will force it to recompute
387 // the analysis.
388 if (!EnableCSE)
389 Wrapper.setComputed(false);
390 return Result.Changed;
391}

/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h

1//===-- llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h -----*- C++ -*-//
2//
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
6//
7//===----------------------------------------------------------------------===//
8// This file contains some helper functions which try to cleanup artifacts
9// such as G_TRUNCs/G_[ZSA]EXTENDS that were created during legalization to make
10// the types match. This file also contains some combines of merges that happens
11// at the end of the legalization.
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZATIONARTIFACTCOMBINER_H
15#define LLVM_CODEGEN_GLOBALISEL_LEGALIZATIONARTIFACTCOMBINER_H
16
17#include "llvm/ADT/SmallBitVector.h"
18#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
19#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
20#include "llvm/CodeGen/GlobalISel/Legalizer.h"
21#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
22#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
23#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
24#include "llvm/CodeGen/GlobalISel/Utils.h"
25#include "llvm/CodeGen/MachineRegisterInfo.h"
26#include "llvm/CodeGen/Register.h"
27#include "llvm/Support/Debug.h"
28
29#define DEBUG_TYPE"legalizer" "legalizer"
30using namespace llvm::MIPatternMatch;
31
32namespace llvm {
33class LegalizationArtifactCombiner {
34 MachineIRBuilder &Builder;
35 MachineRegisterInfo &MRI;
36 const LegalizerInfo &LI;
37
38 static bool isArtifactCast(unsigned Opc) {
39 switch (Opc) {
40 case TargetOpcode::G_TRUNC:
41 case TargetOpcode::G_SEXT:
42 case TargetOpcode::G_ZEXT:
43 case TargetOpcode::G_ANYEXT:
44 return true;
45 default:
46 return false;
47 }
48 }
49
50public:
51 LegalizationArtifactCombiner(MachineIRBuilder &B, MachineRegisterInfo &MRI,
52 const LegalizerInfo &LI)
53 : Builder(B), MRI(MRI), LI(LI) {}
54
55 bool tryCombineAnyExt(MachineInstr &MI,
56 SmallVectorImpl<MachineInstr *> &DeadInsts,
57 SmallVectorImpl<Register> &UpdatedDefs,
58 GISelObserverWrapper &Observer) {
59 assert(MI.getOpcode() == TargetOpcode::G_ANYEXT)(static_cast <bool> (MI.getOpcode() == TargetOpcode::G_ANYEXT
) ? void (0) : __assert_fail ("MI.getOpcode() == TargetOpcode::G_ANYEXT"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 59, __extension__ __PRETTY_FUNCTION__))
;
60
61 Builder.setInstrAndDebugLoc(MI);
62 Register DstReg = MI.getOperand(0).getReg();
63 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
64
65 // aext(trunc x) - > aext/copy/trunc x
66 Register TruncSrc;
67 if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc)))) {
68 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Combine MI: " << MI
;; } } while (false)
;
69 if (MRI.getType(DstReg) == MRI.getType(TruncSrc))
70 replaceRegOrBuildCopy(DstReg, TruncSrc, MRI, Builder, UpdatedDefs,
71 Observer);
72 else
73 Builder.buildAnyExtOrTrunc(DstReg, TruncSrc);
74 UpdatedDefs.push_back(DstReg);
75 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
76 return true;
77 }
78
79 // aext([asz]ext x) -> [asz]ext x
80 Register ExtSrc;
81 MachineInstr *ExtMI;
82 if (mi_match(SrcReg, MRI,
83 m_all_of(m_MInstr(ExtMI), m_any_of(m_GAnyExt(m_Reg(ExtSrc)),
84 m_GSExt(m_Reg(ExtSrc)),
85 m_GZExt(m_Reg(ExtSrc)))))) {
86 Builder.buildInstr(ExtMI->getOpcode(), {DstReg}, {ExtSrc});
87 UpdatedDefs.push_back(DstReg);
88 markInstAndDefDead(MI, *ExtMI, DeadInsts);
89 return true;
90 }
91
92 // Try to fold aext(g_constant) when the larger constant type is legal.
93 auto *SrcMI = MRI.getVRegDef(SrcReg);
94 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
95 const LLT DstTy = MRI.getType(DstReg);
96 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
97 auto &CstVal = SrcMI->getOperand(1);
98 Builder.buildConstant(
99 DstReg, CstVal.getCImm()->getValue().sext(DstTy.getSizeInBits()));
100 UpdatedDefs.push_back(DstReg);
101 markInstAndDefDead(MI, *SrcMI, DeadInsts);
102 return true;
103 }
104 }
105 return tryFoldImplicitDef(MI, DeadInsts, UpdatedDefs);
106 }
107
108 bool tryCombineZExt(MachineInstr &MI,
109 SmallVectorImpl<MachineInstr *> &DeadInsts,
110 SmallVectorImpl<Register> &UpdatedDefs,
111 GISelObserverWrapper &Observer) {
112 assert(MI.getOpcode() == TargetOpcode::G_ZEXT)(static_cast <bool> (MI.getOpcode() == TargetOpcode::G_ZEXT
) ? void (0) : __assert_fail ("MI.getOpcode() == TargetOpcode::G_ZEXT"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 112, __extension__ __PRETTY_FUNCTION__))
;
113
114 Builder.setInstrAndDebugLoc(MI);
115 Register DstReg = MI.getOperand(0).getReg();
116 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
117
118 // zext(trunc x) - > and (aext/copy/trunc x), mask
119 // zext(sext x) -> and (sext x), mask
120 Register TruncSrc;
121 Register SextSrc;
122 if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc))) ||
123 mi_match(SrcReg, MRI, m_GSExt(m_Reg(SextSrc)))) {
124 LLT DstTy = MRI.getType(DstReg);
125 if (isInstUnsupported({TargetOpcode::G_AND, {DstTy}}) ||
126 isConstantUnsupported(DstTy))
127 return false;
128 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Combine MI: " << MI
;; } } while (false)
;
129 LLT SrcTy = MRI.getType(SrcReg);
130 APInt MaskVal = APInt::getAllOnes(SrcTy.getScalarSizeInBits());
131 auto Mask = Builder.buildConstant(
132 DstTy, MaskVal.zext(DstTy.getScalarSizeInBits()));
133 if (SextSrc && (DstTy != MRI.getType(SextSrc)))
134 SextSrc = Builder.buildSExtOrTrunc(DstTy, SextSrc).getReg(0);
135 if (TruncSrc && (DstTy != MRI.getType(TruncSrc)))
136 TruncSrc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrc).getReg(0);
137 Builder.buildAnd(DstReg, SextSrc ? SextSrc : TruncSrc, Mask);
138 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
139 return true;
140 }
141
142 // zext(zext x) -> (zext x)
143 Register ZextSrc;
144 if (mi_match(SrcReg, MRI, m_GZExt(m_Reg(ZextSrc)))) {
145 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Combine MI: " << MI
; } } while (false)
;
146 Observer.changingInstr(MI);
147 MI.getOperand(1).setReg(ZextSrc);
148 Observer.changedInstr(MI);
149 UpdatedDefs.push_back(DstReg);
150 markDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
151 return true;
152 }
153
154 // Try to fold zext(g_constant) when the larger constant type is legal.
155 auto *SrcMI = MRI.getVRegDef(SrcReg);
156 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
157 const LLT DstTy = MRI.getType(DstReg);
158 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
159 auto &CstVal = SrcMI->getOperand(1);
160 Builder.buildConstant(
161 DstReg, CstVal.getCImm()->getValue().zext(DstTy.getSizeInBits()));
162 UpdatedDefs.push_back(DstReg);
163 markInstAndDefDead(MI, *SrcMI, DeadInsts);
164 return true;
165 }
166 }
167 return tryFoldImplicitDef(MI, DeadInsts, UpdatedDefs);
168 }
169
170 bool tryCombineSExt(MachineInstr &MI,
171 SmallVectorImpl<MachineInstr *> &DeadInsts,
172 SmallVectorImpl<Register> &UpdatedDefs) {
173 assert(MI.getOpcode() == TargetOpcode::G_SEXT)(static_cast <bool> (MI.getOpcode() == TargetOpcode::G_SEXT
) ? void (0) : __assert_fail ("MI.getOpcode() == TargetOpcode::G_SEXT"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 173, __extension__ __PRETTY_FUNCTION__))
;
174
175 Builder.setInstrAndDebugLoc(MI);
176 Register DstReg = MI.getOperand(0).getReg();
177 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
178
179 // sext(trunc x) - > (sext_inreg (aext/copy/trunc x), c)
180 Register TruncSrc;
181 if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc)))) {
182 LLT DstTy = MRI.getType(DstReg);
183 if (isInstUnsupported({TargetOpcode::G_SEXT_INREG, {DstTy}}))
184 return false;
185 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Combine MI: " << MI
;; } } while (false)
;
186 LLT SrcTy = MRI.getType(SrcReg);
187 uint64_t SizeInBits = SrcTy.getScalarSizeInBits();
188 if (DstTy != MRI.getType(TruncSrc))
189 TruncSrc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrc).getReg(0);
190 Builder.buildSExtInReg(DstReg, TruncSrc, SizeInBits);
191 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
192 return true;
193 }
194
195 // sext(zext x) -> (zext x)
196 // sext(sext x) -> (sext x)
197 Register ExtSrc;
198 MachineInstr *ExtMI;
199 if (mi_match(SrcReg, MRI,
200 m_all_of(m_MInstr(ExtMI), m_any_of(m_GZExt(m_Reg(ExtSrc)),
201 m_GSExt(m_Reg(ExtSrc)))))) {
202 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Combine MI: " << MI
; } } while (false)
;
203 Builder.buildInstr(ExtMI->getOpcode(), {DstReg}, {ExtSrc});
204 UpdatedDefs.push_back(DstReg);
205 markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
206 return true;
207 }
208
209 // Try to fold sext(g_constant) when the larger constant type is legal.
210 auto *SrcMI = MRI.getVRegDef(SrcReg);
211 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
212 const LLT DstTy = MRI.getType(DstReg);
213 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
214 auto &CstVal = SrcMI->getOperand(1);
215 Builder.buildConstant(
216 DstReg, CstVal.getCImm()->getValue().sext(DstTy.getSizeInBits()));
217 UpdatedDefs.push_back(DstReg);
218 markInstAndDefDead(MI, *SrcMI, DeadInsts);
219 return true;
220 }
221 }
222
223 return tryFoldImplicitDef(MI, DeadInsts, UpdatedDefs);
224 }
225
226 bool tryCombineTrunc(MachineInstr &MI,
227 SmallVectorImpl<MachineInstr *> &DeadInsts,
228 SmallVectorImpl<Register> &UpdatedDefs,
229 GISelObserverWrapper &Observer) {
230 assert(MI.getOpcode() == TargetOpcode::G_TRUNC)(static_cast <bool> (MI.getOpcode() == TargetOpcode::G_TRUNC
) ? void (0) : __assert_fail ("MI.getOpcode() == TargetOpcode::G_TRUNC"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 230, __extension__ __PRETTY_FUNCTION__))
;
231
232 Builder.setInstr(MI);
233 Register DstReg = MI.getOperand(0).getReg();
234 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
235
236 // Try to fold trunc(g_constant) when the smaller constant type is legal.
237 auto *SrcMI = MRI.getVRegDef(SrcReg);
238 if (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT) {
239 const LLT DstTy = MRI.getType(DstReg);
240 if (isInstLegal({TargetOpcode::G_CONSTANT, {DstTy}})) {
241 auto &CstVal = SrcMI->getOperand(1);
242 Builder.buildConstant(
243 DstReg, CstVal.getCImm()->getValue().trunc(DstTy.getSizeInBits()));
244 UpdatedDefs.push_back(DstReg);
245 markInstAndDefDead(MI, *SrcMI, DeadInsts);
246 return true;
247 }
248 }
249
250 // Try to fold trunc(merge) to directly use the source of the merge.
251 // This gets rid of large, difficult to legalize, merges
252 if (auto *SrcMerge = dyn_cast<GMerge>(SrcMI)) {
253 const Register MergeSrcReg = SrcMerge->getSourceReg(0);
254 const LLT MergeSrcTy = MRI.getType(MergeSrcReg);
255 const LLT DstTy = MRI.getType(DstReg);
256
257 // We can only fold if the types are scalar
258 const unsigned DstSize = DstTy.getSizeInBits();
259 const unsigned MergeSrcSize = MergeSrcTy.getSizeInBits();
260 if (!DstTy.isScalar() || !MergeSrcTy.isScalar())
261 return false;
262
263 if (DstSize < MergeSrcSize) {
264 // When the merge source is larger than the destination, we can just
265 // truncate the merge source directly
266 if (isInstUnsupported({TargetOpcode::G_TRUNC, {DstTy, MergeSrcTy}}))
267 return false;
268
269 LLVM_DEBUG(dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_TRUNC: "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_TRUNC: "
<< MI; } } while (false)
270 << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_TRUNC: "
<< MI; } } while (false)
;
271
272 Builder.buildTrunc(DstReg, MergeSrcReg);
273 UpdatedDefs.push_back(DstReg);
274 } else if (DstSize == MergeSrcSize) {
275 // If the sizes match we can simply try to replace the register
276 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Replacing G_TRUNC(G_MERGE_VALUES) with merge input: "
<< MI; } } while (false)
277 dbgs() << "Replacing G_TRUNC(G_MERGE_VALUES) with merge input: "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Replacing G_TRUNC(G_MERGE_VALUES) with merge input: "
<< MI; } } while (false)
278 << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Replacing G_TRUNC(G_MERGE_VALUES) with merge input: "
<< MI; } } while (false)
;
279 replaceRegOrBuildCopy(DstReg, MergeSrcReg, MRI, Builder, UpdatedDefs,
280 Observer);
281 } else if (DstSize % MergeSrcSize == 0) {
282 // If the trunc size is a multiple of the merge source size we can use
283 // a smaller merge instead
284 if (isInstUnsupported(
285 {TargetOpcode::G_MERGE_VALUES, {DstTy, MergeSrcTy}}))
286 return false;
287
288 LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_MERGE_VALUES: "
<< MI; } } while (false)
289 dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_MERGE_VALUES: "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_MERGE_VALUES: "
<< MI; } } while (false)
290 << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << "Combining G_TRUNC(G_MERGE_VALUES) to G_MERGE_VALUES: "
<< MI; } } while (false)
;
291
292 const unsigned NumSrcs = DstSize / MergeSrcSize;
293 assert(NumSrcs < SrcMI->getNumOperands() - 1 &&(static_cast <bool> (NumSrcs < SrcMI->getNumOperands
() - 1 && "trunc(merge) should require less inputs than merge"
) ? void (0) : __assert_fail ("NumSrcs < SrcMI->getNumOperands() - 1 && \"trunc(merge) should require less inputs than merge\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 294, __extension__ __PRETTY_FUNCTION__))
294 "trunc(merge) should require less inputs than merge")(static_cast <bool> (NumSrcs < SrcMI->getNumOperands
() - 1 && "trunc(merge) should require less inputs than merge"
) ? void (0) : __assert_fail ("NumSrcs < SrcMI->getNumOperands() - 1 && \"trunc(merge) should require less inputs than merge\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 294, __extension__ __PRETTY_FUNCTION__))
;
295 SmallVector<Register, 8> SrcRegs(NumSrcs);
296 for (unsigned i = 0; i < NumSrcs; ++i)
297 SrcRegs[i] = SrcMerge->getSourceReg(i);
298
299 Builder.buildMerge(DstReg, SrcRegs);
300 UpdatedDefs.push_back(DstReg);
301 } else {
302 // Unable to combine
303 return false;
304 }
305
306 markInstAndDefDead(MI, *SrcMerge, DeadInsts);
307 return true;
308 }
309
310 // trunc(trunc) -> trunc
311 Register TruncSrc;
312 if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc)))) {
313 // Always combine trunc(trunc) since the eventual resulting trunc must be
314 // legal anyway as it must be legal for all outputs of the consumer type
315 // set.
316 LLVM_DEBUG(dbgs() << ".. Combine G_TRUNC(G_TRUNC): " << MI)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Combine G_TRUNC(G_TRUNC): "
<< MI; } } while (false)
;
317
318 Builder.buildTrunc(DstReg, TruncSrc);
319 UpdatedDefs.push_back(DstReg);
320 markInstAndDefDead(MI, *MRI.getVRegDef(TruncSrc), DeadInsts);
321 return true;
322 }
323
324 return false;
325 }
326
327 /// Try to fold G_[ASZ]EXT (G_IMPLICIT_DEF).
328 bool tryFoldImplicitDef(MachineInstr &MI,
329 SmallVectorImpl<MachineInstr *> &DeadInsts,
330 SmallVectorImpl<Register> &UpdatedDefs) {
331 unsigned Opcode = MI.getOpcode();
332 assert(Opcode == TargetOpcode::G_ANYEXT || Opcode == TargetOpcode::G_ZEXT ||(static_cast <bool> (Opcode == TargetOpcode::G_ANYEXT ||
Opcode == TargetOpcode::G_ZEXT || Opcode == TargetOpcode::G_SEXT
) ? void (0) : __assert_fail ("Opcode == TargetOpcode::G_ANYEXT || Opcode == TargetOpcode::G_ZEXT || Opcode == TargetOpcode::G_SEXT"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 333, __extension__ __PRETTY_FUNCTION__))
333 Opcode == TargetOpcode::G_SEXT)(static_cast <bool> (Opcode == TargetOpcode::G_ANYEXT ||
Opcode == TargetOpcode::G_ZEXT || Opcode == TargetOpcode::G_SEXT
) ? void (0) : __assert_fail ("Opcode == TargetOpcode::G_ANYEXT || Opcode == TargetOpcode::G_ZEXT || Opcode == TargetOpcode::G_SEXT"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 333, __extension__ __PRETTY_FUNCTION__))
;
334
335 if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
336 MI.getOperand(1).getReg(), MRI)) {
337 Builder.setInstr(MI);
338 Register DstReg = MI.getOperand(0).getReg();
339 LLT DstTy = MRI.getType(DstReg);
340
341 if (Opcode == TargetOpcode::G_ANYEXT) {
342 // G_ANYEXT (G_IMPLICIT_DEF) -> G_IMPLICIT_DEF
343 if (!isInstLegal({TargetOpcode::G_IMPLICIT_DEF, {DstTy}}))
344 return false;
345 LLVM_DEBUG(dbgs() << ".. Combine G_ANYEXT(G_IMPLICIT_DEF): " << MI;)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Combine G_ANYEXT(G_IMPLICIT_DEF): "
<< MI;; } } while (false)
;
346 Builder.buildInstr(TargetOpcode::G_IMPLICIT_DEF, {DstReg}, {});
347 UpdatedDefs.push_back(DstReg);
348 } else {
349 // G_[SZ]EXT (G_IMPLICIT_DEF) -> G_CONSTANT 0 because the top
350 // bits will be 0 for G_ZEXT and 0/1 for the G_SEXT.
351 if (isConstantUnsupported(DstTy))
352 return false;
353 LLVM_DEBUG(dbgs() << ".. Combine G_[SZ]EXT(G_IMPLICIT_DEF): " << MI;)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << ".. Combine G_[SZ]EXT(G_IMPLICIT_DEF): "
<< MI;; } } while (false)
;
354 Builder.buildConstant(DstReg, 0);
355 UpdatedDefs.push_back(DstReg);
356 }
357
358 markInstAndDefDead(MI, *DefMI, DeadInsts);
359 return true;
360 }
361 return false;
362 }
363
364 bool tryFoldUnmergeCast(MachineInstr &MI, MachineInstr &CastMI,
365 SmallVectorImpl<MachineInstr *> &DeadInsts,
366 SmallVectorImpl<Register> &UpdatedDefs) {
367
368 assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES)(static_cast <bool> (MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES
) ? void (0) : __assert_fail ("MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 368, __extension__ __PRETTY_FUNCTION__))
;
40
Assuming the condition is true
41
'?' condition is true
369
370 const unsigned CastOpc = CastMI.getOpcode();
371
372 if (!isArtifactCast(CastOpc))
42
Assuming the condition is false
43
Taking false branch
373 return false;
374
375 const unsigned NumDefs = MI.getNumOperands() - 1;
44
'NumDefs' initialized to 0
376
377 const Register CastSrcReg = CastMI.getOperand(1).getReg();
378 const LLT CastSrcTy = MRI.getType(CastSrcReg);
379 const LLT DestTy = MRI.getType(MI.getOperand(0).getReg());
380 const LLT SrcTy = MRI.getType(MI.getOperand(NumDefs).getReg());
381
382 const unsigned CastSrcSize = CastSrcTy.getSizeInBits();
383 const unsigned DestSize = DestTy.getSizeInBits();
384
385 if (CastOpc
44.1
'CastOpc' is equal to G_TRUNC
44.1
'CastOpc' is equal to G_TRUNC
== TargetOpcode::G_TRUNC) {
386 if (SrcTy.isVector() && SrcTy.getScalarType() == DestTy.getScalarType()) {
45
Assuming the condition is true
46
Assuming the condition is true
387 // %1:_(<4 x s8>) = G_TRUNC %0(<4 x s32>)
388 // %2:_(s8), %3:_(s8), %4:_(s8), %5:_(s8) = G_UNMERGE_VALUES %1
389 // =>
390 // %6:_(s32), %7:_(s32), %8:_(s32), %9:_(s32) = G_UNMERGE_VALUES %0
391 // %2:_(s8) = G_TRUNC %6
392 // %3:_(s8) = G_TRUNC %7
393 // %4:_(s8) = G_TRUNC %8
394 // %5:_(s8) = G_TRUNC %9
395
396 unsigned UnmergeNumElts =
47
Taking true branch
397 DestTy.isVector() ? CastSrcTy.getNumElements() / NumDefs : 1;
48
Assuming the condition is true
49
'?' condition is true
50
Division by zero
398 LLT UnmergeTy = CastSrcTy.changeElementCount(
399 ElementCount::getFixed(UnmergeNumElts));
400
401 if (isInstUnsupported(
402 {TargetOpcode::G_UNMERGE_VALUES, {UnmergeTy, CastSrcTy}}))
403 return false;
404
405 Builder.setInstr(MI);
406 auto NewUnmerge = Builder.buildUnmerge(UnmergeTy, CastSrcReg);
407
408 for (unsigned I = 0; I != NumDefs; ++I) {
409 Register DefReg = MI.getOperand(I).getReg();
410 UpdatedDefs.push_back(DefReg);
411 Builder.buildTrunc(DefReg, NewUnmerge.getReg(I));
412 }
413
414 markInstAndDefDead(MI, CastMI, DeadInsts);
415 return true;
416 }
417
418 if (CastSrcTy.isScalar() && SrcTy.isScalar() && !DestTy.isVector()) {
419 // %1:_(s16) = G_TRUNC %0(s32)
420 // %2:_(s8), %3:_(s8) = G_UNMERGE_VALUES %1
421 // =>
422 // %2:_(s8), %3:_(s8), %4:_(s8), %5:_(s8) = G_UNMERGE_VALUES %0
423
424 // Unmerge(trunc) can be combined if the trunc source size is a multiple
425 // of the unmerge destination size
426 if (CastSrcSize % DestSize != 0)
427 return false;
428
429 // Check if the new unmerge is supported
430 if (isInstUnsupported(
431 {TargetOpcode::G_UNMERGE_VALUES, {DestTy, CastSrcTy}}))
432 return false;
433
434 // Gather the original destination registers and create new ones for the
435 // unused bits
436 const unsigned NewNumDefs = CastSrcSize / DestSize;
437 SmallVector<Register, 8> DstRegs(NewNumDefs);
438 for (unsigned Idx = 0; Idx < NewNumDefs; ++Idx) {
439 if (Idx < NumDefs)
440 DstRegs[Idx] = MI.getOperand(Idx).getReg();
441 else
442 DstRegs[Idx] = MRI.createGenericVirtualRegister(DestTy);
443 }
444
445 // Build new unmerge
446 Builder.setInstr(MI);
447 Builder.buildUnmerge(DstRegs, CastSrcReg);
448 UpdatedDefs.append(DstRegs.begin(), DstRegs.begin() + NewNumDefs);
449 markInstAndDefDead(MI, CastMI, DeadInsts);
450 return true;
451 }
452 }
453
454 // TODO: support combines with other casts as well
455 return false;
456 }
457
458 static bool canFoldMergeOpcode(unsigned MergeOp, unsigned ConvertOp,
459 LLT OpTy, LLT DestTy) {
460 // Check if we found a definition that is like G_MERGE_VALUES.
461 switch (MergeOp) {
462 default:
463 return false;
464 case TargetOpcode::G_BUILD_VECTOR:
465 case TargetOpcode::G_MERGE_VALUES:
466 // The convert operation that we will need to insert is
467 // going to convert the input of that type of instruction (scalar)
468 // to the destination type (DestTy).
469 // The conversion needs to stay in the same domain (scalar to scalar
470 // and vector to vector), so if we were to allow to fold the merge
471 // we would need to insert some bitcasts.
472 // E.g.,
473 // <2 x s16> = build_vector s16, s16
474 // <2 x s32> = zext <2 x s16>
475 // <2 x s16>, <2 x s16> = unmerge <2 x s32>
476 //
477 // As is the folding would produce:
478 // <2 x s16> = zext s16 <-- scalar to vector
479 // <2 x s16> = zext s16 <-- scalar to vector
480 // Which is invalid.
481 // Instead we would want to generate:
482 // s32 = zext s16
483 // <2 x s16> = bitcast s32
484 // s32 = zext s16
485 // <2 x s16> = bitcast s32
486 //
487 // That is not done yet.
488 if (ConvertOp == 0)
489 return true;
490 return !DestTy.isVector() && OpTy.isVector();
491 case TargetOpcode::G_CONCAT_VECTORS: {
492 if (ConvertOp == 0)
493 return true;
494 if (!DestTy.isVector())
495 return false;
496
497 const unsigned OpEltSize = OpTy.getElementType().getSizeInBits();
498
499 // Don't handle scalarization with a cast that isn't in the same
500 // direction as the vector cast. This could be handled, but it would
501 // require more intermediate unmerges.
502 if (ConvertOp == TargetOpcode::G_TRUNC)
503 return DestTy.getSizeInBits() <= OpEltSize;
504 return DestTy.getSizeInBits() >= OpEltSize;
505 }
506 }
507 }
508
509 /// Try to replace DstReg with SrcReg or build a COPY instruction
510 /// depending on the register constraints.
511 static void replaceRegOrBuildCopy(Register DstReg, Register SrcReg,
512 MachineRegisterInfo &MRI,
513 MachineIRBuilder &Builder,
514 SmallVectorImpl<Register> &UpdatedDefs,
515 GISelChangeObserver &Observer) {
516 if (!llvm::canReplaceReg(DstReg, SrcReg, MRI)) {
517 Builder.buildCopy(DstReg, SrcReg);
518 UpdatedDefs.push_back(DstReg);
519 return;
520 }
521 SmallVector<MachineInstr *, 4> UseMIs;
522 // Get the users and notify the observer before replacing.
523 for (auto &UseMI : MRI.use_instructions(DstReg)) {
524 UseMIs.push_back(&UseMI);
525 Observer.changingInstr(UseMI);
526 }
527 // Replace the registers.
528 MRI.replaceRegWith(DstReg, SrcReg);
529 UpdatedDefs.push_back(SrcReg);
530 // Notify the observer that we changed the instructions.
531 for (auto *UseMI : UseMIs)
532 Observer.changedInstr(*UseMI);
533 }
534
535 /// Return the operand index in \p MI that defines \p Def
536 static unsigned getDefIndex(const MachineInstr &MI, Register SearchDef) {
537 unsigned DefIdx = 0;
538 for (const MachineOperand &Def : MI.defs()) {
539 if (Def.getReg() == SearchDef)
540 break;
541 ++DefIdx;
542 }
543
544 return DefIdx;
545 }
546
547 /// This class provides utilities for finding source registers of specific
548 /// bit ranges in an artifact. The routines can look through the source
549 /// registers if they're other artifacts to try to find a non-artifact source
550 /// of a value.
551 class ArtifactValueFinder {
552 MachineRegisterInfo &MRI;
553 MachineIRBuilder &MIB;
554 const LegalizerInfo &LI;
555
556 // Stores the best register found in the current query so far.
557 Register CurrentBest = Register();
558
559 /// Given an concat_vector op \p Concat and a start bit and size, try to
560 /// find the origin of the value defined by that start position and size.
561 ///
562 /// \returns a register with the requested size, or the current best
563 /// register found during the current query.
564 Register findValueFromConcat(GConcatVectors &Concat, unsigned StartBit,
565 unsigned Size) {
566 assert(Size > 0)(static_cast <bool> (Size > 0) ? void (0) : __assert_fail
("Size > 0", "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 566, __extension__ __PRETTY_FUNCTION__))
;
567
568 // Find the source operand that provides the bits requested.
569 Register Src1Reg = Concat.getSourceReg(0);
570 unsigned SrcSize = MRI.getType(Src1Reg).getSizeInBits();
571
572 // Operand index of the source that provides the start of the bit range.
573 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
574 // Offset into the source at which the bit range starts.
575 unsigned InRegOffset = StartBit % SrcSize;
576 // Check that the bits don't span multiple sources.
577 // FIXME: we might be able return multiple sources? Or create an
578 // appropriate concat to make it fit.
579 if (InRegOffset + Size > SrcSize)
580 return CurrentBest;
581
582 Register SrcReg = Concat.getReg(StartSrcIdx);
583 if (InRegOffset == 0 && Size == SrcSize) {
584 CurrentBest = SrcReg;
585 return findValueFromDefImpl(SrcReg, 0, Size);
586 }
587
588 return findValueFromDefImpl(SrcReg, InRegOffset, Size);
589 }
590
591 /// Given an build_vector op \p BV and a start bit and size, try to find
592 /// the origin of the value defined by that start position and size.
593 ///
594 /// \returns a register with the requested size, or the current best
595 /// register found during the current query.
596 Register findValueFromBuildVector(GBuildVector &BV, unsigned StartBit,
597 unsigned Size) {
598 assert(Size > 0)(static_cast <bool> (Size > 0) ? void (0) : __assert_fail
("Size > 0", "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 598, __extension__ __PRETTY_FUNCTION__))
;
599
600 // Find the source operand that provides the bits requested.
601 Register Src1Reg = BV.getSourceReg(0);
602 unsigned SrcSize = MRI.getType(Src1Reg).getSizeInBits();
603
604 // Operand index of the source that provides the start of the bit range.
605 unsigned StartSrcIdx = (StartBit / SrcSize) + 1;
606 // Offset into the source at which the bit range starts.
607 unsigned InRegOffset = StartBit % SrcSize;
608
609 if (InRegOffset != 0)
610 return CurrentBest; // Give up, bits don't start at a scalar source.
611 if (Size < SrcSize)
612 return CurrentBest; // Scalar source is too large for requested bits.
613
614 // If the bits cover multiple sources evenly, then create a new
615 // build_vector to synthesize the required size, if that's been requested.
616 if (Size > SrcSize) {
617 if (Size % SrcSize > 0)
618 return CurrentBest; // Isn't covered exactly by sources.
619
620 unsigned NumSrcsUsed = Size / SrcSize;
621 // If we're requesting all of the sources, just return this def.
622 if (NumSrcsUsed == BV.getNumSources())
623 return BV.getReg(0);
624
625 LLT SrcTy = MRI.getType(Src1Reg);
626 LLT NewBVTy = LLT::fixed_vector(NumSrcsUsed, SrcTy);
627
628 // Check if the resulting build vector would be legal.
629 LegalizeActionStep ActionStep =
630 LI.getAction({TargetOpcode::G_BUILD_VECTOR, {NewBVTy, SrcTy}});
631 if (ActionStep.Action != LegalizeActions::Legal)
632 return CurrentBest;
633
634 SmallVector<Register> NewSrcs;
635 for (unsigned SrcIdx = StartSrcIdx; SrcIdx < StartSrcIdx + NumSrcsUsed;
636 ++SrcIdx)
637 NewSrcs.push_back(BV.getReg(SrcIdx));
638 MIB.setInstrAndDebugLoc(BV);
639 return MIB.buildBuildVector(NewBVTy, NewSrcs).getReg(0);
640 }
641 // A single source is requested, just return it.
642 return BV.getReg(StartSrcIdx);
643 }
644
645 /// Given an G_INSERT op \p MI and a start bit and size, try to find
646 /// the origin of the value defined by that start position and size.
647 ///
648 /// \returns a register with the requested size, or the current best
649 /// register found during the current query.
650 Register findValueFromInsert(MachineInstr &MI, unsigned StartBit,
651 unsigned Size) {
652 assert(MI.getOpcode() == TargetOpcode::G_INSERT)(static_cast <bool> (MI.getOpcode() == TargetOpcode::G_INSERT
) ? void (0) : __assert_fail ("MI.getOpcode() == TargetOpcode::G_INSERT"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 652, __extension__ __PRETTY_FUNCTION__))
;
653 assert(Size > 0)(static_cast <bool> (Size > 0) ? void (0) : __assert_fail
("Size > 0", "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 653, __extension__ __PRETTY_FUNCTION__))
;
654
655 Register ContainerSrcReg = MI.getOperand(1).getReg();
656 Register InsertedReg = MI.getOperand(2).getReg();
657 LLT InsertedRegTy = MRI.getType(InsertedReg);
658 unsigned InsertOffset = MI.getOperand(3).getImm();
659
660 // There are 4 possible container/insertreg + requested bit-range layouts
661 // that the instruction and query could be representing.
662 // For: %_ = G_INSERT %CONTAINER, %INS, InsOff (abbrev. to 'IO')
663 // and a start bit 'SB', with size S, giving an end bit 'EB', we could
664 // have...
665 // Scenario A:
666 // --------------------------
667 // | INS | CONTAINER |
668 // --------------------------
669 // | |
670 // SB EB
671 //
672 // Scenario B:
673 // --------------------------
674 // | INS | CONTAINER |
675 // --------------------------
676 // | |
677 // SB EB
678 //
679 // Scenario C:
680 // --------------------------
681 // | CONTAINER | INS |
682 // --------------------------
683 // | |
684 // SB EB
685 //
686 // Scenario D:
687 // --------------------------
688 // | CONTAINER | INS |
689 // --------------------------
690 // | |
691 // SB EB
692 //
693 // So therefore, A and D are requesting data from the INS operand, while
694 // B and C are requesting from the container operand.
695
696 unsigned InsertedEndBit = InsertOffset + InsertedRegTy.getSizeInBits();
697 unsigned EndBit = StartBit + Size;
698 unsigned NewStartBit;
699 Register SrcRegToUse;
700 if (EndBit <= InsertOffset || InsertedEndBit <= StartBit) {
701 SrcRegToUse = ContainerSrcReg;
702 NewStartBit = StartBit;
703 return findValueFromDefImpl(SrcRegToUse, NewStartBit, Size);
704 }
705 if (InsertOffset <= StartBit && EndBit <= InsertedEndBit) {
706 SrcRegToUse = InsertedReg;
707 NewStartBit = StartBit - InsertOffset;
708 if (NewStartBit == 0 &&
709 Size == MRI.getType(SrcRegToUse).getSizeInBits())
710 CurrentBest = SrcRegToUse;
711 return findValueFromDefImpl(SrcRegToUse, NewStartBit, Size);
712 }
713 // The bit range spans both the inserted and container regions.
714 return Register();
715 }
716
717 /// Internal implementation for findValueFromDef(). findValueFromDef()
718 /// initializes some data like the CurrentBest register, which this method
719 /// and its callees rely upon.
720 Register findValueFromDefImpl(Register DefReg, unsigned StartBit,
721 unsigned Size) {
722 MachineInstr *Def = getDefIgnoringCopies(DefReg, MRI);
723 // If the instruction has a single def, then simply delegate the search.
724 // For unmerge however with multiple defs, we need to compute the offset
725 // into the source of the unmerge.
726 switch (Def->getOpcode()) {
727 case TargetOpcode::G_CONCAT_VECTORS:
728 return findValueFromConcat(cast<GConcatVectors>(*Def), StartBit, Size);
729 case TargetOpcode::G_UNMERGE_VALUES: {
730 unsigned DefStartBit = 0;
731 unsigned DefSize = MRI.getType(DefReg).getSizeInBits();
732 for (const auto &MO : Def->defs()) {
733 if (MO.getReg() == DefReg)
734 break;
735 DefStartBit += DefSize;
736 }
737 Register SrcReg = Def->getOperand(Def->getNumOperands() - 1).getReg();
738 Register SrcOriginReg =
739 findValueFromDefImpl(SrcReg, StartBit + DefStartBit, Size);
740 if (SrcOriginReg)
741 return SrcOriginReg;
742 // Failed to find a further value. If the StartBit and Size perfectly
743 // covered the requested DefReg, return that since it's better than
744 // nothing.
745 if (StartBit == 0 && Size == DefSize)
746 return DefReg;
747 return CurrentBest;
748 }
749 case TargetOpcode::G_BUILD_VECTOR:
750 return findValueFromBuildVector(cast<GBuildVector>(*Def), StartBit,
751 Size);
752 case TargetOpcode::G_INSERT:
753 return findValueFromInsert(*Def, StartBit, Size);
754 default:
755 return CurrentBest;
756 }
757 }
758
759 public:
760 ArtifactValueFinder(MachineRegisterInfo &Mri, MachineIRBuilder &Builder,
761 const LegalizerInfo &Info)
762 : MRI(Mri), MIB(Builder), LI(Info) {}
763
764 /// Try to find a source of the value defined in the def \p DefReg, starting
765 /// at position \p StartBit with size \p Size.
766 /// \returns a register with the requested size, or an empty Register if no
767 /// better value could be found.
768 Register findValueFromDef(Register DefReg, unsigned StartBit,
769 unsigned Size) {
770 CurrentBest = Register();
771 Register FoundReg = findValueFromDefImpl(DefReg, StartBit, Size);
772 return FoundReg != DefReg ? FoundReg : Register();
773 }
774
775 /// Try to combine the defs of an unmerge \p MI by attempting to find
776 /// values that provides the bits for each def reg.
777 /// \returns true if all the defs of the unmerge have been made dead.
778 bool tryCombineUnmergeDefs(GUnmerge &MI, GISelChangeObserver &Observer,
779 SmallVectorImpl<Register> &UpdatedDefs) {
780 unsigned NumDefs = MI.getNumDefs();
781 LLT DestTy = MRI.getType(MI.getReg(0));
782
783 SmallBitVector DeadDefs(NumDefs);
784 for (unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
785 Register DefReg = MI.getReg(DefIdx);
786 if (MRI.use_nodbg_empty(DefReg)) {
787 DeadDefs[DefIdx] = true;
788 continue;
789 }
790 Register FoundVal = findValueFromDef(DefReg, 0, DestTy.getSizeInBits());
791 if (!FoundVal)
792 continue;
793 if (MRI.getType(FoundVal) != DestTy)
794 continue;
795
796 replaceRegOrBuildCopy(DefReg, FoundVal, MRI, MIB, UpdatedDefs,
797 Observer);
798 // We only want to replace the uses, not the def of the old reg.
799 Observer.changingInstr(MI);
800 MI.getOperand(DefIdx).setReg(DefReg);
801 Observer.changedInstr(MI);
802 DeadDefs[DefIdx] = true;
803 }
804 return DeadDefs.all();
805 }
806 };
807
808 bool tryCombineUnmergeValues(GUnmerge &MI,
809 SmallVectorImpl<MachineInstr *> &DeadInsts,
810 SmallVectorImpl<Register> &UpdatedDefs,
811 GISelChangeObserver &Observer) {
812 unsigned NumDefs = MI.getNumDefs();
813 Register SrcReg = MI.getSourceReg();
814 MachineInstr *SrcDef = getDefIgnoringCopies(SrcReg, MRI);
815 if (!SrcDef)
31
Assuming 'SrcDef' is non-null
32
Taking false branch
816 return false;
817
818 LLT OpTy = MRI.getType(SrcReg);
819 LLT DestTy = MRI.getType(MI.getReg(0));
820 unsigned SrcDefIdx = getDefIndex(*SrcDef, SrcReg);
821
822 Builder.setInstrAndDebugLoc(MI);
823
824 ArtifactValueFinder Finder(MRI, Builder, LI);
825 if (Finder.tryCombineUnmergeDefs(MI, Observer, UpdatedDefs)) {
33
Assuming the condition is false
34
Taking false branch
826 markInstAndDefDead(MI, *SrcDef, DeadInsts, SrcDefIdx);
827 return true;
828 }
829
830 if (auto *SrcUnmerge
35.1
'SrcUnmerge' is null
35.1
'SrcUnmerge' is null
= dyn_cast<GUnmerge>(SrcDef)) {
35
Assuming 'SrcDef' is not a 'GUnmerge'
36
Taking false branch
831 // %0:_(<4 x s16>) = G_FOO
832 // %1:_(<2 x s16>), %2:_(<2 x s16>) = G_UNMERGE_VALUES %0
833 // %3:_(s16), %4:_(s16) = G_UNMERGE_VALUES %1
834 //
835 // %3:_(s16), %4:_(s16), %5:_(s16), %6:_(s16) = G_UNMERGE_VALUES %0
836 Register SrcUnmergeSrc = SrcUnmerge->getSourceReg();
837 LLT SrcUnmergeSrcTy = MRI.getType(SrcUnmergeSrc);
838
839 // If we need to decrease the number of vector elements in the result type
840 // of an unmerge, this would involve the creation of an equivalent unmerge
841 // to copy back to the original result registers.
842 LegalizeActionStep ActionStep = LI.getAction(
843 {TargetOpcode::G_UNMERGE_VALUES, {OpTy, SrcUnmergeSrcTy}});
844 switch (ActionStep.Action) {
845 case LegalizeActions::Lower:
846 case LegalizeActions::Unsupported:
847 break;
848 case LegalizeActions::FewerElements:
849 case LegalizeActions::NarrowScalar:
850 if (ActionStep.TypeIdx == 1)
851 return false;
852 break;
853 default:
854 return false;
855 }
856
857 auto NewUnmerge = Builder.buildUnmerge(DestTy, SrcUnmergeSrc);
858
859 // TODO: Should we try to process out the other defs now? If the other
860 // defs of the source unmerge are also unmerged, we end up with a separate
861 // unmerge for each one.
862 for (unsigned I = 0; I != NumDefs; ++I) {
863 Register Def = MI.getReg(I);
864 replaceRegOrBuildCopy(Def, NewUnmerge.getReg(SrcDefIdx * NumDefs + I),
865 MRI, Builder, UpdatedDefs, Observer);
866 }
867
868 markInstAndDefDead(MI, *SrcUnmerge, DeadInsts, SrcDefIdx);
869 return true;
870 }
871
872 MachineInstr *MergeI = SrcDef;
873 unsigned ConvertOp = 0;
874
875 // Handle intermediate conversions
876 unsigned SrcOp = SrcDef->getOpcode();
877 if (isArtifactCast(SrcOp)) {
37
Taking true branch
878 ConvertOp = SrcOp;
879 MergeI = getDefIgnoringCopies(SrcDef->getOperand(1).getReg(), MRI);
880 }
881
882 if (!MergeI || !canFoldMergeOpcode(MergeI->getOpcode(),
38
Assuming 'MergeI' is null
883 ConvertOp, OpTy, DestTy)) {
884 // We might have a chance to combine later by trying to combine
885 // unmerge(cast) first
886 return tryFoldUnmergeCast(MI, *SrcDef, DeadInsts, UpdatedDefs);
39
Calling 'LegalizationArtifactCombiner::tryFoldUnmergeCast'
887 }
888
889 const unsigned NumMergeRegs = MergeI->getNumOperands() - 1;
890
891 if (NumMergeRegs < NumDefs) {
892 if (NumDefs % NumMergeRegs != 0)
893 return false;
894
895 Builder.setInstr(MI);
896 // Transform to UNMERGEs, for example
897 // %1 = G_MERGE_VALUES %4, %5
898 // %9, %10, %11, %12 = G_UNMERGE_VALUES %1
899 // to
900 // %9, %10 = G_UNMERGE_VALUES %4
901 // %11, %12 = G_UNMERGE_VALUES %5
902
903 const unsigned NewNumDefs = NumDefs / NumMergeRegs;
904 for (unsigned Idx = 0; Idx < NumMergeRegs; ++Idx) {
905 SmallVector<Register, 8> DstRegs;
906 for (unsigned j = 0, DefIdx = Idx * NewNumDefs; j < NewNumDefs;
907 ++j, ++DefIdx)
908 DstRegs.push_back(MI.getReg(DefIdx));
909
910 if (ConvertOp) {
911 LLT MergeSrcTy = MRI.getType(MergeI->getOperand(1).getReg());
912
913 // This is a vector that is being split and casted. Extract to the
914 // element type, and do the conversion on the scalars (or smaller
915 // vectors).
916 LLT MergeEltTy = MergeSrcTy.divide(NewNumDefs);
917
918 // Handle split to smaller vectors, with conversions.
919 // %2(<8 x s8>) = G_CONCAT_VECTORS %0(<4 x s8>), %1(<4 x s8>)
920 // %3(<8 x s16>) = G_SEXT %2
921 // %4(<2 x s16>), %5(<2 x s16>), %6(<2 x s16>), %7(<2 x s16>) = G_UNMERGE_VALUES %3
922 //
923 // =>
924 //
925 // %8(<2 x s8>), %9(<2 x s8>) = G_UNMERGE_VALUES %0
926 // %10(<2 x s8>), %11(<2 x s8>) = G_UNMERGE_VALUES %1
927 // %4(<2 x s16>) = G_SEXT %8
928 // %5(<2 x s16>) = G_SEXT %9
929 // %6(<2 x s16>) = G_SEXT %10
930 // %7(<2 x s16>)= G_SEXT %11
931
932 SmallVector<Register, 4> TmpRegs(NewNumDefs);
933 for (unsigned k = 0; k < NewNumDefs; ++k)
934 TmpRegs[k] = MRI.createGenericVirtualRegister(MergeEltTy);
935
936 Builder.buildUnmerge(TmpRegs, MergeI->getOperand(Idx + 1).getReg());
937
938 for (unsigned k = 0; k < NewNumDefs; ++k)
939 Builder.buildInstr(ConvertOp, {DstRegs[k]}, {TmpRegs[k]});
940 } else {
941 Builder.buildUnmerge(DstRegs, MergeI->getOperand(Idx + 1).getReg());
942 }
943 UpdatedDefs.append(DstRegs.begin(), DstRegs.end());
944 }
945
946 } else if (NumMergeRegs > NumDefs) {
947 if (ConvertOp != 0 || NumMergeRegs % NumDefs != 0)
948 return false;
949
950 Builder.setInstr(MI);
951 // Transform to MERGEs
952 // %6 = G_MERGE_VALUES %17, %18, %19, %20
953 // %7, %8 = G_UNMERGE_VALUES %6
954 // to
955 // %7 = G_MERGE_VALUES %17, %18
956 // %8 = G_MERGE_VALUES %19, %20
957
958 const unsigned NumRegs = NumMergeRegs / NumDefs;
959 for (unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) {
960 SmallVector<Register, 8> Regs;
961 for (unsigned j = 0, Idx = NumRegs * DefIdx + 1; j < NumRegs;
962 ++j, ++Idx)
963 Regs.push_back(MergeI->getOperand(Idx).getReg());
964
965 Register DefReg = MI.getReg(DefIdx);
966 Builder.buildMerge(DefReg, Regs);
967 UpdatedDefs.push_back(DefReg);
968 }
969
970 } else {
971 LLT MergeSrcTy = MRI.getType(MergeI->getOperand(1).getReg());
972
973 if (!ConvertOp && DestTy != MergeSrcTy)
974 ConvertOp = TargetOpcode::G_BITCAST;
975
976 if (ConvertOp) {
977 Builder.setInstr(MI);
978
979 for (unsigned Idx = 0; Idx < NumDefs; ++Idx) {
980 Register MergeSrc = MergeI->getOperand(Idx + 1).getReg();
981 Register DefReg = MI.getOperand(Idx).getReg();
982 Builder.buildInstr(ConvertOp, {DefReg}, {MergeSrc});
983 UpdatedDefs.push_back(DefReg);
984 }
985
986 markInstAndDefDead(MI, *MergeI, DeadInsts);
987 return true;
988 }
989
990 assert(DestTy == MergeSrcTy &&(static_cast <bool> (DestTy == MergeSrcTy && "Bitcast and the other kinds of conversions should "
"have happened earlier") ? void (0) : __assert_fail ("DestTy == MergeSrcTy && \"Bitcast and the other kinds of conversions should \" \"have happened earlier\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 992, __extension__ __PRETTY_FUNCTION__))
991 "Bitcast and the other kinds of conversions should "(static_cast <bool> (DestTy == MergeSrcTy && "Bitcast and the other kinds of conversions should "
"have happened earlier") ? void (0) : __assert_fail ("DestTy == MergeSrcTy && \"Bitcast and the other kinds of conversions should \" \"have happened earlier\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 992, __extension__ __PRETTY_FUNCTION__))
992 "have happened earlier")(static_cast <bool> (DestTy == MergeSrcTy && "Bitcast and the other kinds of conversions should "
"have happened earlier") ? void (0) : __assert_fail ("DestTy == MergeSrcTy && \"Bitcast and the other kinds of conversions should \" \"have happened earlier\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 992, __extension__ __PRETTY_FUNCTION__))
;
993
994 Builder.setInstr(MI);
995 for (unsigned Idx = 0; Idx < NumDefs; ++Idx) {
996 Register DstReg = MI.getOperand(Idx).getReg();
997 Register SrcReg = MergeI->getOperand(Idx + 1).getReg();
998 replaceRegOrBuildCopy(DstReg, SrcReg, MRI, Builder, UpdatedDefs,
999 Observer);
1000 }
1001 }
1002
1003 markInstAndDefDead(MI, *MergeI, DeadInsts);
1004 return true;
1005 }
1006
1007 bool tryCombineExtract(MachineInstr &MI,
1008 SmallVectorImpl<MachineInstr *> &DeadInsts,
1009 SmallVectorImpl<Register> &UpdatedDefs) {
1010 assert(MI.getOpcode() == TargetOpcode::G_EXTRACT)(static_cast <bool> (MI.getOpcode() == TargetOpcode::G_EXTRACT
) ? void (0) : __assert_fail ("MI.getOpcode() == TargetOpcode::G_EXTRACT"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 1010, __extension__ __PRETTY_FUNCTION__))
;
1011
1012 // Try to use the source registers from a G_MERGE_VALUES
1013 //
1014 // %2 = G_MERGE_VALUES %0, %1
1015 // %3 = G_EXTRACT %2, N
1016 // =>
1017 //
1018 // for N < %2.getSizeInBits() / 2
1019 // %3 = G_EXTRACT %0, N
1020 //
1021 // for N >= %2.getSizeInBits() / 2
1022 // %3 = G_EXTRACT %1, (N - %0.getSizeInBits()
1023
1024 Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
1025 MachineInstr *MergeI = MRI.getVRegDef(SrcReg);
1026 if (!MergeI || !isa<GMergeLikeOp>(MergeI))
1027 return false;
1028
1029 Register DstReg = MI.getOperand(0).getReg();
1030 LLT DstTy = MRI.getType(DstReg);
1031 LLT SrcTy = MRI.getType(SrcReg);
1032
1033 // TODO: Do we need to check if the resulting extract is supported?
1034 unsigned ExtractDstSize = DstTy.getSizeInBits();
1035 unsigned Offset = MI.getOperand(2).getImm();
1036 unsigned NumMergeSrcs = MergeI->getNumOperands() - 1;
1037 unsigned MergeSrcSize = SrcTy.getSizeInBits() / NumMergeSrcs;
1038 unsigned MergeSrcIdx = Offset / MergeSrcSize;
1039
1040 // Compute the offset of the last bit the extract needs.
1041 unsigned EndMergeSrcIdx = (Offset + ExtractDstSize - 1) / MergeSrcSize;
1042
1043 // Can't handle the case where the extract spans multiple inputs.
1044 if (MergeSrcIdx != EndMergeSrcIdx)
1045 return false;
1046
1047 // TODO: We could modify MI in place in most cases.
1048 Builder.setInstr(MI);
1049 Builder.buildExtract(DstReg, MergeI->getOperand(MergeSrcIdx + 1).getReg(),
1050 Offset - MergeSrcIdx * MergeSrcSize);
1051 UpdatedDefs.push_back(DstReg);
1052 markInstAndDefDead(MI, *MergeI, DeadInsts);
1053 return true;
1054 }
1055
1056 /// Try to combine away MI.
1057 /// Returns true if it combined away the MI.
1058 /// Adds instructions that are dead as a result of the combine
1059 /// into DeadInsts, which can include MI.
1060 bool tryCombineInstruction(MachineInstr &MI,
1061 SmallVectorImpl<MachineInstr *> &DeadInsts,
1062 GISelObserverWrapper &WrapperObserver) {
1063 // This might be a recursive call, and we might have DeadInsts already
1064 // populated. To avoid bad things happening later with multiple vreg defs
1065 // etc, process the dead instructions now if any.
1066 if (!DeadInsts.empty())
27
Taking true branch
1067 deleteMarkedDeadInsts(DeadInsts, WrapperObserver);
1068
1069 // Put here every vreg that was redefined in such a way that it's at least
1070 // possible that one (or more) of its users (immediate or COPY-separated)
1071 // could become artifact combinable with the new definition (or the
1072 // instruction reachable from it through a chain of copies if any).
1073 SmallVector<Register, 4> UpdatedDefs;
1074 bool Changed = false;
1075 switch (MI.getOpcode()) {
28
Control jumps to 'case G_UNMERGE_VALUES:' at line 1087
1076 default:
1077 return false;
1078 case TargetOpcode::G_ANYEXT:
1079 Changed = tryCombineAnyExt(MI, DeadInsts, UpdatedDefs, WrapperObserver);
1080 break;
1081 case TargetOpcode::G_ZEXT:
1082 Changed = tryCombineZExt(MI, DeadInsts, UpdatedDefs, WrapperObserver);
1083 break;
1084 case TargetOpcode::G_SEXT:
1085 Changed = tryCombineSExt(MI, DeadInsts, UpdatedDefs);
1086 break;
1087 case TargetOpcode::G_UNMERGE_VALUES:
1088 Changed = tryCombineUnmergeValues(cast<GUnmerge>(MI), DeadInsts,
29
'MI' is a 'GUnmerge'
30
Calling 'LegalizationArtifactCombiner::tryCombineUnmergeValues'
1089 UpdatedDefs, WrapperObserver);
1090 break;
1091 case TargetOpcode::G_MERGE_VALUES:
1092 case TargetOpcode::G_BUILD_VECTOR:
1093 case TargetOpcode::G_CONCAT_VECTORS:
1094 // If any of the users of this merge are an unmerge, then add them to the
1095 // artifact worklist in case there's folding that can be done looking up.
1096 for (MachineInstr &U : MRI.use_instructions(MI.getOperand(0).getReg())) {
1097 if (U.getOpcode() == TargetOpcode::G_UNMERGE_VALUES ||
1098 U.getOpcode() == TargetOpcode::G_TRUNC) {
1099 UpdatedDefs.push_back(MI.getOperand(0).getReg());
1100 break;
1101 }
1102 }
1103 break;
1104 case TargetOpcode::G_EXTRACT:
1105 Changed = tryCombineExtract(MI, DeadInsts, UpdatedDefs);
1106 break;
1107 case TargetOpcode::G_TRUNC:
1108 Changed = tryCombineTrunc(MI, DeadInsts, UpdatedDefs, WrapperObserver);
1109 if (!Changed) {
1110 // Try to combine truncates away even if they are legal. As all artifact
1111 // combines at the moment look only "up" the def-use chains, we achieve
1112 // that by throwing truncates' users (with look through copies) into the
1113 // ArtifactList again.
1114 UpdatedDefs.push_back(MI.getOperand(0).getReg());
1115 }
1116 break;
1117 }
1118 // If the main loop through the ArtifactList found at least one combinable
1119 // pair of artifacts, not only combine it away (as done above), but also
1120 // follow the def-use chain from there to combine everything that can be
1121 // combined within this def-use chain of artifacts.
1122 while (!UpdatedDefs.empty()) {
1123 Register NewDef = UpdatedDefs.pop_back_val();
1124 assert(NewDef.isVirtual() && "Unexpected redefinition of a physreg")(static_cast <bool> (NewDef.isVirtual() && "Unexpected redefinition of a physreg"
) ? void (0) : __assert_fail ("NewDef.isVirtual() && \"Unexpected redefinition of a physreg\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 1124, __extension__ __PRETTY_FUNCTION__))
;
1125 for (MachineInstr &Use : MRI.use_instructions(NewDef)) {
1126 switch (Use.getOpcode()) {
1127 // Keep this list in sync with the list of all artifact combines.
1128 case TargetOpcode::G_ANYEXT:
1129 case TargetOpcode::G_ZEXT:
1130 case TargetOpcode::G_SEXT:
1131 case TargetOpcode::G_UNMERGE_VALUES:
1132 case TargetOpcode::G_EXTRACT:
1133 case TargetOpcode::G_TRUNC:
1134 // Adding Use to ArtifactList.
1135 WrapperObserver.changedInstr(Use);
1136 break;
1137 case TargetOpcode::COPY: {
1138 Register Copy = Use.getOperand(0).getReg();
1139 if (Copy.isVirtual())
1140 UpdatedDefs.push_back(Copy);
1141 break;
1142 }
1143 default:
1144 // If we do not have an artifact combine for the opcode, there is no
1145 // point in adding it to the ArtifactList as nothing interesting will
1146 // be done to it anyway.
1147 break;
1148 }
1149 }
1150 }
1151 return Changed;
1152 }
1153
1154private:
1155 static Register getArtifactSrcReg(const MachineInstr &MI) {
1156 switch (MI.getOpcode()) {
1157 case TargetOpcode::COPY:
1158 case TargetOpcode::G_TRUNC:
1159 case TargetOpcode::G_ZEXT:
1160 case TargetOpcode::G_ANYEXT:
1161 case TargetOpcode::G_SEXT:
1162 case TargetOpcode::G_EXTRACT:
1163 return MI.getOperand(1).getReg();
1164 case TargetOpcode::G_UNMERGE_VALUES:
1165 return MI.getOperand(MI.getNumOperands() - 1).getReg();
1166 default:
1167 llvm_unreachable("Not a legalization artifact happen")::llvm::llvm_unreachable_internal("Not a legalization artifact happen"
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 1167)
;
1168 }
1169 }
1170
1171 /// Mark a def of one of MI's original operands, DefMI, as dead if changing MI
1172 /// (either by killing it or changing operands) results in DefMI being dead
1173 /// too. In-between COPYs or artifact-casts are also collected if they are
1174 /// dead.
1175 /// MI is not marked dead.
1176 void markDefDead(MachineInstr &MI, MachineInstr &DefMI,
1177 SmallVectorImpl<MachineInstr *> &DeadInsts,
1178 unsigned DefIdx = 0) {
1179 // Collect all the copy instructions that are made dead, due to deleting
1180 // this instruction. Collect all of them until the Trunc(DefMI).
1181 // Eg,
1182 // %1(s1) = G_TRUNC %0(s32)
1183 // %2(s1) = COPY %1(s1)
1184 // %3(s1) = COPY %2(s1)
1185 // %4(s32) = G_ANYEXT %3(s1)
1186 // In this case, we would have replaced %4 with a copy of %0,
1187 // and as a result, %3, %2, %1 are dead.
1188 MachineInstr *PrevMI = &MI;
1189 while (PrevMI != &DefMI) {
1190 Register PrevRegSrc = getArtifactSrcReg(*PrevMI);
1191
1192 MachineInstr *TmpDef = MRI.getVRegDef(PrevRegSrc);
1193 if (MRI.hasOneUse(PrevRegSrc)) {
1194 if (TmpDef != &DefMI) {
1195 assert((TmpDef->getOpcode() == TargetOpcode::COPY ||(static_cast <bool> ((TmpDef->getOpcode() == TargetOpcode
::COPY || isArtifactCast(TmpDef->getOpcode())) && "Expecting copy or artifact cast here"
) ? void (0) : __assert_fail ("(TmpDef->getOpcode() == TargetOpcode::COPY || isArtifactCast(TmpDef->getOpcode())) && \"Expecting copy or artifact cast here\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 1197, __extension__ __PRETTY_FUNCTION__))
1196 isArtifactCast(TmpDef->getOpcode())) &&(static_cast <bool> ((TmpDef->getOpcode() == TargetOpcode
::COPY || isArtifactCast(TmpDef->getOpcode())) && "Expecting copy or artifact cast here"
) ? void (0) : __assert_fail ("(TmpDef->getOpcode() == TargetOpcode::COPY || isArtifactCast(TmpDef->getOpcode())) && \"Expecting copy or artifact cast here\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 1197, __extension__ __PRETTY_FUNCTION__))
1197 "Expecting copy or artifact cast here")(static_cast <bool> ((TmpDef->getOpcode() == TargetOpcode
::COPY || isArtifactCast(TmpDef->getOpcode())) && "Expecting copy or artifact cast here"
) ? void (0) : __assert_fail ("(TmpDef->getOpcode() == TargetOpcode::COPY || isArtifactCast(TmpDef->getOpcode())) && \"Expecting copy or artifact cast here\""
, "/build/llvm-toolchain-snapshot-14~++20211016100712+8e1d532707fd/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
, 1197, __extension__ __PRETTY_FUNCTION__))
;
1198
1199 DeadInsts.push_back(TmpDef);
1200 }
1201 } else
1202 break;
1203 PrevMI = TmpDef;
1204 }
1205
1206 if (PrevMI == &DefMI) {
1207 unsigned I = 0;
1208 bool IsDead = true;
1209 for (MachineOperand &Def : DefMI.defs()) {
1210 if (I != DefIdx) {
1211 if (!MRI.use_empty(Def.getReg())) {
1212 IsDead = false;
1213 break;
1214 }
1215 } else {
1216 if (!MRI.hasOneUse(DefMI.getOperand(DefIdx).getReg()))
1217 break;
1218 }
1219
1220 ++I;
1221 }
1222
1223 if (IsDead)
1224 DeadInsts.push_back(&DefMI);
1225 }
1226 }
1227
1228 /// Mark MI as dead. If a def of one of MI's operands, DefMI, would also be
1229 /// dead due to MI being killed, then mark DefMI as dead too.
1230 /// Some of the combines (extends(trunc)), try to walk through redundant
1231 /// copies in between the extends and the truncs, and this attempts to collect
1232 /// the in between copies if they're dead.
1233 void markInstAndDefDead(MachineInstr &MI, MachineInstr &DefMI,
1234 SmallVectorImpl<MachineInstr *> &DeadInsts,
1235 unsigned DefIdx = 0) {
1236 DeadInsts.push_back(&MI);
1237 markDefDead(MI, DefMI, DeadInsts, DefIdx);
1238 }
1239
1240 /// Erase the dead instructions in the list and call the observer hooks.
1241 /// Normally the Legalizer will deal with erasing instructions that have been
1242 /// marked dead. However, for the trunc(ext(x)) cases we can end up trying to
1243 /// process instructions which have been marked dead, but otherwise break the
1244 /// MIR by introducing multiple vreg defs. For those cases, allow the combines
1245 /// to explicitly delete the instructions before we run into trouble.
1246 void deleteMarkedDeadInsts(SmallVectorImpl<MachineInstr *> &DeadInsts,
1247 GISelObserverWrapper &WrapperObserver) {
1248 for (auto *DeadMI : DeadInsts) {
1249 LLVM_DEBUG(dbgs() << *DeadMI << "Is dead, eagerly deleting\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("legalizer")) { dbgs() << *DeadMI << "Is dead, eagerly deleting\n"
; } } while (false)
;
1250 WrapperObserver.erasingInstr(*DeadMI);
1251 DeadMI->eraseFromParentAndMarkDBGValuesForRemoval();
1252 }
1253 DeadInsts.clear();
1254 }
1255
1256 /// Checks if the target legalizer info has specified anything about the
1257 /// instruction, or if unsupported.
1258 bool isInstUnsupported(const LegalityQuery &Query) const {
1259 using namespace LegalizeActions;
1260 auto Step = LI.getAction(Query);
1261 return Step.Action == Unsupported || Step.Action == NotFound;
1262 }
1263
1264 bool isInstLegal(const LegalityQuery &Query) const {
1265 return LI.getAction(Query).Action == LegalizeActions::Legal;
1266 }
1267
1268 bool isConstantUnsupported(LLT Ty) const {
1269 if (!Ty.isVector())
1270 return isInstUnsupported({TargetOpcode::G_CONSTANT, {Ty}});
1271
1272 LLT EltTy = Ty.getElementType();
1273 return isInstUnsupported({TargetOpcode::G_CONSTANT, {EltTy}}) ||
1274 isInstUnsupported({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}});
1275 }
1276
1277 /// Looks through copy instructions and returns the actual
1278 /// source register.
1279 Register lookThroughCopyInstrs(Register Reg) {
1280 Register TmpReg;
1281 while (mi_match(Reg, MRI, m_Copy(m_Reg(TmpReg)))) {
1282 if (MRI.getType(TmpReg).isValid())
1283 Reg = TmpReg;
1284 else
1285 break;
1286 }
1287 return Reg;
1288 }
1289};
1290
1291} // namespace llvm
1292
1293#endif // LLVM_CODEGEN_GLOBALISEL_LEGALIZATIONARTIFACTCOMBINER_H