Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
Warning:line 401, 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-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 -ffp-contract=on -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-16~++20221003111214+1fa2019828ca/build-llvm -resource-dir /usr/lib/llvm-16/lib/clang/16.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-16~++20221003111214+1fa2019828ca/llvm/lib/CodeGen/GlobalISel -I include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include -D _FORTIFY_SOURCE=2 -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-16/lib/clang/16.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 -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -O3 -Wno-unused-command-line-argument -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 -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -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-2022-10-03-140002-15933-1 -x c++ /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp

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

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