1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceCfg.cpp - Control flow graph implementation ---------===//
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // The Subzero Code Generator
4*03ce13f7SAndroid Build Coastguard Worker //
5*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*03ce13f7SAndroid Build Coastguard Worker //
8*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*03ce13f7SAndroid Build Coastguard Worker ///
10*03ce13f7SAndroid Build Coastguard Worker /// \file
11*03ce13f7SAndroid Build Coastguard Worker /// \brief Implements the Cfg class.
12*03ce13f7SAndroid Build Coastguard Worker ///
13*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #include "IceCfg.h"
16*03ce13f7SAndroid Build Coastguard Worker
17*03ce13f7SAndroid Build Coastguard Worker #include "IceAssembler.h"
18*03ce13f7SAndroid Build Coastguard Worker #include "IceBitVector.h"
19*03ce13f7SAndroid Build Coastguard Worker #include "IceCfgNode.h"
20*03ce13f7SAndroid Build Coastguard Worker #include "IceClFlags.h"
21*03ce13f7SAndroid Build Coastguard Worker #include "IceDefs.h"
22*03ce13f7SAndroid Build Coastguard Worker #include "IceELFObjectWriter.h"
23*03ce13f7SAndroid Build Coastguard Worker #include "IceGlobalInits.h"
24*03ce13f7SAndroid Build Coastguard Worker #include "IceInst.h"
25*03ce13f7SAndroid Build Coastguard Worker #include "IceInstVarIter.h"
26*03ce13f7SAndroid Build Coastguard Worker #include "IceInstrumentation.h"
27*03ce13f7SAndroid Build Coastguard Worker #include "IceLiveness.h"
28*03ce13f7SAndroid Build Coastguard Worker #include "IceLoopAnalyzer.h"
29*03ce13f7SAndroid Build Coastguard Worker #include "IceOperand.h"
30*03ce13f7SAndroid Build Coastguard Worker #include "IceTargetLowering.h"
31*03ce13f7SAndroid Build Coastguard Worker
32*03ce13f7SAndroid Build Coastguard Worker #include <memory>
33*03ce13f7SAndroid Build Coastguard Worker #include <utility>
34*03ce13f7SAndroid Build Coastguard Worker
35*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
36*03ce13f7SAndroid Build Coastguard Worker
Cfg(GlobalContext * Ctx,uint32_t SequenceNumber)37*03ce13f7SAndroid Build Coastguard Worker Cfg::Cfg(GlobalContext *Ctx, uint32_t SequenceNumber)
38*03ce13f7SAndroid Build Coastguard Worker : Allocator(createAllocator()), Ctx(Ctx), SequenceNumber(SequenceNumber),
39*03ce13f7SAndroid Build Coastguard Worker VMask(getFlags().getVerbose()), FunctionName(),
40*03ce13f7SAndroid Build Coastguard Worker NextInstNumber(Inst::NumberInitial), Live(nullptr) {
41*03ce13f7SAndroid Build Coastguard Worker NodeStrings.reset(new StringPool);
42*03ce13f7SAndroid Build Coastguard Worker VarStrings.reset(new StringPool);
43*03ce13f7SAndroid Build Coastguard Worker CfgLocalAllocatorScope _(this);
44*03ce13f7SAndroid Build Coastguard Worker Target = TargetLowering::createLowering(getFlags().getTargetArch(), this);
45*03ce13f7SAndroid Build Coastguard Worker VMetadata.reset(new VariablesMetadata(this));
46*03ce13f7SAndroid Build Coastguard Worker TargetAssembler = Target->createAssembler();
47*03ce13f7SAndroid Build Coastguard Worker }
48*03ce13f7SAndroid Build Coastguard Worker
~Cfg()49*03ce13f7SAndroid Build Coastguard Worker Cfg::~Cfg() {
50*03ce13f7SAndroid Build Coastguard Worker assert(CfgAllocatorTraits::current() == nullptr);
51*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getDumpStrings()) {
52*03ce13f7SAndroid Build Coastguard Worker OstreamLocker _(Ctx);
53*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrDump();
54*03ce13f7SAndroid Build Coastguard Worker getNodeStrings()->dump(Str);
55*03ce13f7SAndroid Build Coastguard Worker getVarStrings()->dump(Str);
56*03ce13f7SAndroid Build Coastguard Worker }
57*03ce13f7SAndroid Build Coastguard Worker }
58*03ce13f7SAndroid Build Coastguard Worker
59*03ce13f7SAndroid Build Coastguard Worker // Called in the initalizer list of Cfg's constructor to create the Allocator
60*03ce13f7SAndroid Build Coastguard Worker // and set it as TLS before any other member fields are constructed, since they
61*03ce13f7SAndroid Build Coastguard Worker // may depend on it.
createAllocator()62*03ce13f7SAndroid Build Coastguard Worker ArenaAllocator *Cfg::createAllocator() {
63*03ce13f7SAndroid Build Coastguard Worker ArenaAllocator *Allocator = new ArenaAllocator();
64*03ce13f7SAndroid Build Coastguard Worker CfgAllocatorTraits::set_current(Allocator);
65*03ce13f7SAndroid Build Coastguard Worker return Allocator;
66*03ce13f7SAndroid Build Coastguard Worker }
67*03ce13f7SAndroid Build Coastguard Worker
68*03ce13f7SAndroid Build Coastguard Worker /// Create a string like "foo(i=123:b=9)" indicating the function name, number
69*03ce13f7SAndroid Build Coastguard Worker /// of high-level instructions, and number of basic blocks. This string is only
70*03ce13f7SAndroid Build Coastguard Worker /// used for dumping and other diagnostics, and the idea is that given a set of
71*03ce13f7SAndroid Build Coastguard Worker /// functions to debug a problem on, it's easy to find the smallest or simplest
72*03ce13f7SAndroid Build Coastguard Worker /// function to attack. Note that the counts may change somewhat depending on
73*03ce13f7SAndroid Build Coastguard Worker /// what point it is called during the translation passes.
getFunctionNameAndSize() const74*03ce13f7SAndroid Build Coastguard Worker std::string Cfg::getFunctionNameAndSize() const {
75*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
76*03ce13f7SAndroid Build Coastguard Worker return getFunctionName().toString();
77*03ce13f7SAndroid Build Coastguard Worker SizeT NodeCount = 0;
78*03ce13f7SAndroid Build Coastguard Worker SizeT InstCount = 0;
79*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : getNodes()) {
80*03ce13f7SAndroid Build Coastguard Worker ++NodeCount;
81*03ce13f7SAndroid Build Coastguard Worker // Note: deleted instructions are *not* ignored.
82*03ce13f7SAndroid Build Coastguard Worker InstCount += Node->getPhis().size();
83*03ce13f7SAndroid Build Coastguard Worker for (Inst &I : Node->getInsts()) {
84*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<InstTarget>(&I))
85*03ce13f7SAndroid Build Coastguard Worker ++InstCount;
86*03ce13f7SAndroid Build Coastguard Worker }
87*03ce13f7SAndroid Build Coastguard Worker }
88*03ce13f7SAndroid Build Coastguard Worker return getFunctionName() + "(i=" + std::to_string(InstCount) +
89*03ce13f7SAndroid Build Coastguard Worker ":b=" + std::to_string(NodeCount) + ")";
90*03ce13f7SAndroid Build Coastguard Worker }
91*03ce13f7SAndroid Build Coastguard Worker
setError(const std::string & Message)92*03ce13f7SAndroid Build Coastguard Worker void Cfg::setError(const std::string &Message) {
93*03ce13f7SAndroid Build Coastguard Worker HasError = true;
94*03ce13f7SAndroid Build Coastguard Worker ErrorMessage = Message;
95*03ce13f7SAndroid Build Coastguard Worker }
96*03ce13f7SAndroid Build Coastguard Worker
makeNode()97*03ce13f7SAndroid Build Coastguard Worker CfgNode *Cfg::makeNode() {
98*03ce13f7SAndroid Build Coastguard Worker SizeT LabelIndex = Nodes.size();
99*03ce13f7SAndroid Build Coastguard Worker auto *Node = CfgNode::create(this, LabelIndex);
100*03ce13f7SAndroid Build Coastguard Worker Nodes.push_back(Node);
101*03ce13f7SAndroid Build Coastguard Worker return Node;
102*03ce13f7SAndroid Build Coastguard Worker }
103*03ce13f7SAndroid Build Coastguard Worker
swapNodes(NodeList & NewNodes)104*03ce13f7SAndroid Build Coastguard Worker void Cfg::swapNodes(NodeList &NewNodes) {
105*03ce13f7SAndroid Build Coastguard Worker assert(Nodes.size() == NewNodes.size());
106*03ce13f7SAndroid Build Coastguard Worker Nodes.swap(NewNodes);
107*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0, NumNodes = getNumNodes(); I < NumNodes; ++I)
108*03ce13f7SAndroid Build Coastguard Worker Nodes[I]->resetIndex(I);
109*03ce13f7SAndroid Build Coastguard Worker }
110*03ce13f7SAndroid Build Coastguard Worker
makeVariable(Type Ty)111*03ce13f7SAndroid Build Coastguard Worker template <> Variable *Cfg::makeVariable<Variable>(Type Ty) {
112*03ce13f7SAndroid Build Coastguard Worker SizeT Index = Variables.size();
113*03ce13f7SAndroid Build Coastguard Worker Variable *Var;
114*03ce13f7SAndroid Build Coastguard Worker if (Target->shouldSplitToVariableVecOn32(Ty)) {
115*03ce13f7SAndroid Build Coastguard Worker Var = VariableVecOn32::create(this, Ty, Index);
116*03ce13f7SAndroid Build Coastguard Worker } else if (Target->shouldSplitToVariable64On32(Ty)) {
117*03ce13f7SAndroid Build Coastguard Worker Var = Variable64On32::create(this, Ty, Index);
118*03ce13f7SAndroid Build Coastguard Worker } else {
119*03ce13f7SAndroid Build Coastguard Worker Var = Variable::create(this, Ty, Index);
120*03ce13f7SAndroid Build Coastguard Worker }
121*03ce13f7SAndroid Build Coastguard Worker Variables.push_back(Var);
122*03ce13f7SAndroid Build Coastguard Worker return Var;
123*03ce13f7SAndroid Build Coastguard Worker }
124*03ce13f7SAndroid Build Coastguard Worker
addArg(Variable * Arg)125*03ce13f7SAndroid Build Coastguard Worker void Cfg::addArg(Variable *Arg) {
126*03ce13f7SAndroid Build Coastguard Worker Arg->setIsArg();
127*03ce13f7SAndroid Build Coastguard Worker Args.push_back(Arg);
128*03ce13f7SAndroid Build Coastguard Worker }
129*03ce13f7SAndroid Build Coastguard Worker
addImplicitArg(Variable * Arg)130*03ce13f7SAndroid Build Coastguard Worker void Cfg::addImplicitArg(Variable *Arg) {
131*03ce13f7SAndroid Build Coastguard Worker Arg->setIsImplicitArg();
132*03ce13f7SAndroid Build Coastguard Worker ImplicitArgs.push_back(Arg);
133*03ce13f7SAndroid Build Coastguard Worker }
134*03ce13f7SAndroid Build Coastguard Worker
135*03ce13f7SAndroid Build Coastguard Worker // Returns whether the stack frame layout has been computed yet. This is used
136*03ce13f7SAndroid Build Coastguard Worker // for dumping the stack frame location of Variables.
hasComputedFrame() const137*03ce13f7SAndroid Build Coastguard Worker bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); }
138*03ce13f7SAndroid Build Coastguard Worker
139*03ce13f7SAndroid Build Coastguard Worker namespace {
140*03ce13f7SAndroid Build Coastguard Worker constexpr char BlockNameGlobalPrefix[] = ".L$profiler$block_name$";
141*03ce13f7SAndroid Build Coastguard Worker constexpr char BlockStatsGlobalPrefix[] = ".L$profiler$block_info$";
142*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
143*03ce13f7SAndroid Build Coastguard Worker
createNodeNameDeclaration(const std::string & NodeAsmName)144*03ce13f7SAndroid Build Coastguard Worker void Cfg::createNodeNameDeclaration(const std::string &NodeAsmName) {
145*03ce13f7SAndroid Build Coastguard Worker auto *Var = VariableDeclaration::create(GlobalInits.get());
146*03ce13f7SAndroid Build Coastguard Worker Var->setName(Ctx, BlockNameGlobalPrefix + NodeAsmName);
147*03ce13f7SAndroid Build Coastguard Worker Var->setIsConstant(true);
148*03ce13f7SAndroid Build Coastguard Worker Var->addInitializer(VariableDeclaration::DataInitializer::create(
149*03ce13f7SAndroid Build Coastguard Worker GlobalInits.get(), NodeAsmName.data(), NodeAsmName.size() + 1));
150*03ce13f7SAndroid Build Coastguard Worker const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64);
151*03ce13f7SAndroid Build Coastguard Worker Var->setAlignment(Int64ByteSize); // Wasteful, 32-bit could use 4 bytes.
152*03ce13f7SAndroid Build Coastguard Worker GlobalInits->push_back(Var);
153*03ce13f7SAndroid Build Coastguard Worker }
154*03ce13f7SAndroid Build Coastguard Worker
createBlockProfilingInfoDeclaration(const std::string & NodeAsmName,VariableDeclaration * NodeNameDeclaration)155*03ce13f7SAndroid Build Coastguard Worker void Cfg::createBlockProfilingInfoDeclaration(
156*03ce13f7SAndroid Build Coastguard Worker const std::string &NodeAsmName, VariableDeclaration *NodeNameDeclaration) {
157*03ce13f7SAndroid Build Coastguard Worker auto *Var = VariableDeclaration::create(GlobalInits.get());
158*03ce13f7SAndroid Build Coastguard Worker Var->setName(Ctx, BlockStatsGlobalPrefix + NodeAsmName);
159*03ce13f7SAndroid Build Coastguard Worker const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64);
160*03ce13f7SAndroid Build Coastguard Worker Var->addInitializer(VariableDeclaration::ZeroInitializer::create(
161*03ce13f7SAndroid Build Coastguard Worker GlobalInits.get(), Int64ByteSize));
162*03ce13f7SAndroid Build Coastguard Worker
163*03ce13f7SAndroid Build Coastguard Worker const RelocOffsetT NodeNameDeclarationOffset = 0;
164*03ce13f7SAndroid Build Coastguard Worker Var->addInitializer(VariableDeclaration::RelocInitializer::create(
165*03ce13f7SAndroid Build Coastguard Worker GlobalInits.get(), NodeNameDeclaration,
166*03ce13f7SAndroid Build Coastguard Worker {RelocOffset::create(Ctx, NodeNameDeclarationOffset)}));
167*03ce13f7SAndroid Build Coastguard Worker Var->setAlignment(Int64ByteSize);
168*03ce13f7SAndroid Build Coastguard Worker GlobalInits->push_back(Var);
169*03ce13f7SAndroid Build Coastguard Worker }
170*03ce13f7SAndroid Build Coastguard Worker
translate()171*03ce13f7SAndroid Build Coastguard Worker void Cfg::translate() {
172*03ce13f7SAndroid Build Coastguard Worker if (hasError())
173*03ce13f7SAndroid Build Coastguard Worker return;
174*03ce13f7SAndroid Build Coastguard Worker // Cache the possibly-overridden optimization level once translation begins.
175*03ce13f7SAndroid Build Coastguard Worker // It would be nicer to do this in the constructor, but we need to wait until
176*03ce13f7SAndroid Build Coastguard Worker // after setFunctionName() has a chance to be called.
177*03ce13f7SAndroid Build Coastguard Worker OptimizationLevel =
178*03ce13f7SAndroid Build Coastguard Worker getFlags().matchForceO2(getFunctionName(), getSequenceNumber())
179*03ce13f7SAndroid Build Coastguard Worker ? Opt_2
180*03ce13f7SAndroid Build Coastguard Worker : getFlags().getOptLevel();
181*03ce13f7SAndroid Build Coastguard Worker if (BuildDefs::timers()) {
182*03ce13f7SAndroid Build Coastguard Worker if (getFlags().matchTimingFocus(getFunctionName(), getSequenceNumber())) {
183*03ce13f7SAndroid Build Coastguard Worker setFocusedTiming();
184*03ce13f7SAndroid Build Coastguard Worker getContext()->resetTimer(GlobalContext::TSK_Default);
185*03ce13f7SAndroid Build Coastguard Worker }
186*03ce13f7SAndroid Build Coastguard Worker }
187*03ce13f7SAndroid Build Coastguard Worker if (BuildDefs::dump()) {
188*03ce13f7SAndroid Build Coastguard Worker if (isVerbose(IceV_Status) &&
189*03ce13f7SAndroid Build Coastguard Worker getFlags().matchTestStatus(getFunctionName(), getSequenceNumber())) {
190*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump()
191*03ce13f7SAndroid Build Coastguard Worker << ">>>Translating " << getFunctionNameAndSize()
192*03ce13f7SAndroid Build Coastguard Worker << " seq=" << getSequenceNumber() << "\n";
193*03ce13f7SAndroid Build Coastguard Worker }
194*03ce13f7SAndroid Build Coastguard Worker }
195*03ce13f7SAndroid Build Coastguard Worker TimerMarker T_func(getContext(), getFunctionName().toStringOrEmpty());
196*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_translate, this);
197*03ce13f7SAndroid Build Coastguard Worker
198*03ce13f7SAndroid Build Coastguard Worker dump("Initial CFG");
199*03ce13f7SAndroid Build Coastguard Worker
200*03ce13f7SAndroid Build Coastguard Worker // Create the Hi and Lo variables where a split was needed
201*03ce13f7SAndroid Build Coastguard Worker for (Variable *Var : Variables) {
202*03ce13f7SAndroid Build Coastguard Worker if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Var)) {
203*03ce13f7SAndroid Build Coastguard Worker Var64On32->initHiLo(this);
204*03ce13f7SAndroid Build Coastguard Worker } else if (auto *VarVecOn32 = llvm::dyn_cast<VariableVecOn32>(Var)) {
205*03ce13f7SAndroid Build Coastguard Worker VarVecOn32->initVecElement(this);
206*03ce13f7SAndroid Build Coastguard Worker }
207*03ce13f7SAndroid Build Coastguard Worker }
208*03ce13f7SAndroid Build Coastguard Worker
209*03ce13f7SAndroid Build Coastguard Worker // Instrument the Cfg, e.g. with AddressSanitizer
210*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::minimal() && getFlags().getSanitizeAddresses()) {
211*03ce13f7SAndroid Build Coastguard Worker getContext()->instrumentFunc(this);
212*03ce13f7SAndroid Build Coastguard Worker dump("Instrumented CFG");
213*03ce13f7SAndroid Build Coastguard Worker }
214*03ce13f7SAndroid Build Coastguard Worker
215*03ce13f7SAndroid Build Coastguard Worker // The set of translation passes and their order are determined by the
216*03ce13f7SAndroid Build Coastguard Worker // target.
217*03ce13f7SAndroid Build Coastguard Worker getTarget()->translate();
218*03ce13f7SAndroid Build Coastguard Worker
219*03ce13f7SAndroid Build Coastguard Worker dump("Final output");
220*03ce13f7SAndroid Build Coastguard Worker if (getFocusedTiming()) {
221*03ce13f7SAndroid Build Coastguard Worker getContext()->dumpLocalTimers(getFunctionName().toString());
222*03ce13f7SAndroid Build Coastguard Worker }
223*03ce13f7SAndroid Build Coastguard Worker }
224*03ce13f7SAndroid Build Coastguard Worker
fixPhiNodes()225*03ce13f7SAndroid Build Coastguard Worker void Cfg::fixPhiNodes() {
226*03ce13f7SAndroid Build Coastguard Worker for (auto *Node : Nodes) {
227*03ce13f7SAndroid Build Coastguard Worker // Fix all the phi edges since WASM can't tell how to make them correctly at
228*03ce13f7SAndroid Build Coastguard Worker // the beginning.
229*03ce13f7SAndroid Build Coastguard Worker assert(Node);
230*03ce13f7SAndroid Build Coastguard Worker const auto &InEdges = Node->getInEdges();
231*03ce13f7SAndroid Build Coastguard Worker for (auto &Instr : Node->getPhis()) {
232*03ce13f7SAndroid Build Coastguard Worker auto *Phi = llvm::cast<InstPhi>(&Instr);
233*03ce13f7SAndroid Build Coastguard Worker assert(Phi);
234*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < InEdges.size(); ++i) {
235*03ce13f7SAndroid Build Coastguard Worker Phi->setLabel(i, InEdges[i]);
236*03ce13f7SAndroid Build Coastguard Worker }
237*03ce13f7SAndroid Build Coastguard Worker }
238*03ce13f7SAndroid Build Coastguard Worker }
239*03ce13f7SAndroid Build Coastguard Worker }
240*03ce13f7SAndroid Build Coastguard Worker
computeInOutEdges()241*03ce13f7SAndroid Build Coastguard Worker void Cfg::computeInOutEdges() {
242*03ce13f7SAndroid Build Coastguard Worker // Compute the out-edges.
243*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
244*03ce13f7SAndroid Build Coastguard Worker Node->computeSuccessors();
245*03ce13f7SAndroid Build Coastguard Worker }
246*03ce13f7SAndroid Build Coastguard Worker
247*03ce13f7SAndroid Build Coastguard Worker // Prune any unreachable nodes before computing in-edges.
248*03ce13f7SAndroid Build Coastguard Worker SizeT NumNodes = getNumNodes();
249*03ce13f7SAndroid Build Coastguard Worker BitVector Reachable(NumNodes);
250*03ce13f7SAndroid Build Coastguard Worker BitVector Pending(NumNodes);
251*03ce13f7SAndroid Build Coastguard Worker Pending.set(getEntryNode()->getIndex());
252*03ce13f7SAndroid Build Coastguard Worker while (true) {
253*03ce13f7SAndroid Build Coastguard Worker int Index = Pending.find_first();
254*03ce13f7SAndroid Build Coastguard Worker if (Index == -1)
255*03ce13f7SAndroid Build Coastguard Worker break;
256*03ce13f7SAndroid Build Coastguard Worker Pending.reset(Index);
257*03ce13f7SAndroid Build Coastguard Worker Reachable.set(Index);
258*03ce13f7SAndroid Build Coastguard Worker CfgNode *Node = Nodes[Index];
259*03ce13f7SAndroid Build Coastguard Worker assert(Node->getIndex() == (SizeT)Index);
260*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Succ : Node->getOutEdges()) {
261*03ce13f7SAndroid Build Coastguard Worker SizeT SuccIndex = Succ->getIndex();
262*03ce13f7SAndroid Build Coastguard Worker if (!Reachable.test(SuccIndex))
263*03ce13f7SAndroid Build Coastguard Worker Pending.set(SuccIndex);
264*03ce13f7SAndroid Build Coastguard Worker }
265*03ce13f7SAndroid Build Coastguard Worker }
266*03ce13f7SAndroid Build Coastguard Worker SizeT Dest = 0;
267*03ce13f7SAndroid Build Coastguard Worker for (SizeT Source = 0; Source < NumNodes; ++Source) {
268*03ce13f7SAndroid Build Coastguard Worker if (Reachable.test(Source)) {
269*03ce13f7SAndroid Build Coastguard Worker Nodes[Dest] = Nodes[Source];
270*03ce13f7SAndroid Build Coastguard Worker Nodes[Dest]->resetIndex(Dest);
271*03ce13f7SAndroid Build Coastguard Worker // Compute the in-edges.
272*03ce13f7SAndroid Build Coastguard Worker Nodes[Dest]->computePredecessors();
273*03ce13f7SAndroid Build Coastguard Worker ++Dest;
274*03ce13f7SAndroid Build Coastguard Worker }
275*03ce13f7SAndroid Build Coastguard Worker }
276*03ce13f7SAndroid Build Coastguard Worker Nodes.resize(Dest);
277*03ce13f7SAndroid Build Coastguard Worker
278*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_phiValidation, this);
279*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
280*03ce13f7SAndroid Build Coastguard Worker Node->enforcePhiConsistency();
281*03ce13f7SAndroid Build Coastguard Worker }
282*03ce13f7SAndroid Build Coastguard Worker
renumberInstructions()283*03ce13f7SAndroid Build Coastguard Worker void Cfg::renumberInstructions() {
284*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_renumberInstructions, this);
285*03ce13f7SAndroid Build Coastguard Worker NextInstNumber = Inst::NumberInitial;
286*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
287*03ce13f7SAndroid Build Coastguard Worker Node->renumberInstructions();
288*03ce13f7SAndroid Build Coastguard Worker // Make sure the entry node is the first node and therefore got the lowest
289*03ce13f7SAndroid Build Coastguard Worker // instruction numbers, to facilitate live range computation of function
290*03ce13f7SAndroid Build Coastguard Worker // arguments. We want to model function arguments as being live on entry to
291*03ce13f7SAndroid Build Coastguard Worker // the function, otherwise an argument whose only use is in the first
292*03ce13f7SAndroid Build Coastguard Worker // instruction will be assigned a trivial live range and the register
293*03ce13f7SAndroid Build Coastguard Worker // allocator will not recognize its live range as overlapping another
294*03ce13f7SAndroid Build Coastguard Worker // variable's live range.
295*03ce13f7SAndroid Build Coastguard Worker assert(Nodes.empty() || (*Nodes.begin() == getEntryNode()));
296*03ce13f7SAndroid Build Coastguard Worker }
297*03ce13f7SAndroid Build Coastguard Worker
298*03ce13f7SAndroid Build Coastguard Worker // placePhiLoads() must be called before placePhiStores().
placePhiLoads()299*03ce13f7SAndroid Build Coastguard Worker void Cfg::placePhiLoads() {
300*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_placePhiLoads, this);
301*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
302*03ce13f7SAndroid Build Coastguard Worker Node->placePhiLoads();
303*03ce13f7SAndroid Build Coastguard Worker }
304*03ce13f7SAndroid Build Coastguard Worker
305*03ce13f7SAndroid Build Coastguard Worker // placePhiStores() must be called after placePhiLoads().
placePhiStores()306*03ce13f7SAndroid Build Coastguard Worker void Cfg::placePhiStores() {
307*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_placePhiStores, this);
308*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
309*03ce13f7SAndroid Build Coastguard Worker Node->placePhiStores();
310*03ce13f7SAndroid Build Coastguard Worker }
311*03ce13f7SAndroid Build Coastguard Worker
deletePhis()312*03ce13f7SAndroid Build Coastguard Worker void Cfg::deletePhis() {
313*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_deletePhis, this);
314*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
315*03ce13f7SAndroid Build Coastguard Worker Node->deletePhis();
316*03ce13f7SAndroid Build Coastguard Worker }
317*03ce13f7SAndroid Build Coastguard Worker
advancedPhiLowering()318*03ce13f7SAndroid Build Coastguard Worker void Cfg::advancedPhiLowering() {
319*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_advancedPhiLowering, this);
320*03ce13f7SAndroid Build Coastguard Worker // Clear all previously computed live ranges (but not live-in/live-out bit
321*03ce13f7SAndroid Build Coastguard Worker // vectors or last-use markers), because the follow-on register allocation is
322*03ce13f7SAndroid Build Coastguard Worker // only concerned with live ranges across the newly created blocks.
323*03ce13f7SAndroid Build Coastguard Worker for (Variable *Var : Variables) {
324*03ce13f7SAndroid Build Coastguard Worker Var->getLiveRange().reset();
325*03ce13f7SAndroid Build Coastguard Worker }
326*03ce13f7SAndroid Build Coastguard Worker // This splits edges and appends new nodes to the end of the node list. This
327*03ce13f7SAndroid Build Coastguard Worker // can invalidate iterators, so don't use an iterator.
328*03ce13f7SAndroid Build Coastguard Worker SizeT NumNodes = getNumNodes();
329*03ce13f7SAndroid Build Coastguard Worker SizeT NumVars = getNumVariables();
330*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0; I < NumNodes; ++I)
331*03ce13f7SAndroid Build Coastguard Worker Nodes[I]->advancedPhiLowering();
332*03ce13f7SAndroid Build Coastguard Worker
333*03ce13f7SAndroid Build Coastguard Worker TimerMarker TT(TimerStack::TT_lowerPhiAssignments, this);
334*03ce13f7SAndroid Build Coastguard Worker if (true) {
335*03ce13f7SAndroid Build Coastguard Worker // The following code does an in-place update of liveness and live ranges
336*03ce13f7SAndroid Build Coastguard Worker // as a result of adding the new phi edge split nodes.
337*03ce13f7SAndroid Build Coastguard Worker getLiveness()->initPhiEdgeSplits(Nodes.begin() + NumNodes,
338*03ce13f7SAndroid Build Coastguard Worker Variables.begin() + NumVars);
339*03ce13f7SAndroid Build Coastguard Worker TimerMarker TTT(TimerStack::TT_liveness, this);
340*03ce13f7SAndroid Build Coastguard Worker // Iterate over the newly added nodes to add their liveness info.
341*03ce13f7SAndroid Build Coastguard Worker for (auto I = Nodes.begin() + NumNodes, E = Nodes.end(); I != E; ++I) {
342*03ce13f7SAndroid Build Coastguard Worker InstNumberT FirstInstNum = getNextInstNumber();
343*03ce13f7SAndroid Build Coastguard Worker (*I)->renumberInstructions();
344*03ce13f7SAndroid Build Coastguard Worker InstNumberT LastInstNum = getNextInstNumber() - 1;
345*03ce13f7SAndroid Build Coastguard Worker (*I)->liveness(getLiveness());
346*03ce13f7SAndroid Build Coastguard Worker (*I)->livenessAddIntervals(getLiveness(), FirstInstNum, LastInstNum);
347*03ce13f7SAndroid Build Coastguard Worker }
348*03ce13f7SAndroid Build Coastguard Worker } else {
349*03ce13f7SAndroid Build Coastguard Worker // The following code does a brute-force recalculation of live ranges as a
350*03ce13f7SAndroid Build Coastguard Worker // result of adding the new phi edge split nodes. The liveness calculation
351*03ce13f7SAndroid Build Coastguard Worker // is particularly expensive because the new nodes are not yet in a proper
352*03ce13f7SAndroid Build Coastguard Worker // topological order and so convergence is slower.
353*03ce13f7SAndroid Build Coastguard Worker //
354*03ce13f7SAndroid Build Coastguard Worker // This code is kept here for reference and can be temporarily enabled in
355*03ce13f7SAndroid Build Coastguard Worker // case the incremental code is under suspicion.
356*03ce13f7SAndroid Build Coastguard Worker renumberInstructions();
357*03ce13f7SAndroid Build Coastguard Worker liveness(Liveness_Intervals);
358*03ce13f7SAndroid Build Coastguard Worker getVMetadata()->init(VMK_All);
359*03ce13f7SAndroid Build Coastguard Worker }
360*03ce13f7SAndroid Build Coastguard Worker Target->regAlloc(RAK_Phi);
361*03ce13f7SAndroid Build Coastguard Worker }
362*03ce13f7SAndroid Build Coastguard Worker
363*03ce13f7SAndroid Build Coastguard Worker // Find a reasonable placement for nodes that have not yet been placed, while
364*03ce13f7SAndroid Build Coastguard Worker // maintaining the same relative ordering among already placed nodes.
reorderNodes()365*03ce13f7SAndroid Build Coastguard Worker void Cfg::reorderNodes() {
366*03ce13f7SAndroid Build Coastguard Worker // TODO(ascull): it would be nice if the switch tests were always followed by
367*03ce13f7SAndroid Build Coastguard Worker // the default case to allow for fall through.
368*03ce13f7SAndroid Build Coastguard Worker using PlacedList = CfgList<CfgNode *>;
369*03ce13f7SAndroid Build Coastguard Worker PlacedList Placed; // Nodes with relative placement locked down
370*03ce13f7SAndroid Build Coastguard Worker PlacedList Unreachable; // Unreachable nodes
371*03ce13f7SAndroid Build Coastguard Worker PlacedList::iterator NoPlace = Placed.end();
372*03ce13f7SAndroid Build Coastguard Worker // Keep track of where each node has been tentatively placed so that we can
373*03ce13f7SAndroid Build Coastguard Worker // manage insertions into the middle.
374*03ce13f7SAndroid Build Coastguard Worker CfgVector<PlacedList::iterator> PlaceIndex(Nodes.size(), NoPlace);
375*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
376*03ce13f7SAndroid Build Coastguard Worker // The "do ... while(0);" construct is to factor out the --PlaceIndex and
377*03ce13f7SAndroid Build Coastguard Worker // assert() statements before moving to the next node.
378*03ce13f7SAndroid Build Coastguard Worker do {
379*03ce13f7SAndroid Build Coastguard Worker if (Node != getEntryNode() && Node->getInEdges().empty()) {
380*03ce13f7SAndroid Build Coastguard Worker // The node has essentially been deleted since it is not a successor of
381*03ce13f7SAndroid Build Coastguard Worker // any other node.
382*03ce13f7SAndroid Build Coastguard Worker Unreachable.push_back(Node);
383*03ce13f7SAndroid Build Coastguard Worker PlaceIndex[Node->getIndex()] = Unreachable.end();
384*03ce13f7SAndroid Build Coastguard Worker Node->setNeedsPlacement(false);
385*03ce13f7SAndroid Build Coastguard Worker continue;
386*03ce13f7SAndroid Build Coastguard Worker }
387*03ce13f7SAndroid Build Coastguard Worker if (!Node->needsPlacement()) {
388*03ce13f7SAndroid Build Coastguard Worker // Add to the end of the Placed list.
389*03ce13f7SAndroid Build Coastguard Worker Placed.push_back(Node);
390*03ce13f7SAndroid Build Coastguard Worker PlaceIndex[Node->getIndex()] = Placed.end();
391*03ce13f7SAndroid Build Coastguard Worker continue;
392*03ce13f7SAndroid Build Coastguard Worker }
393*03ce13f7SAndroid Build Coastguard Worker Node->setNeedsPlacement(false);
394*03ce13f7SAndroid Build Coastguard Worker // Assume for now that the unplaced node is from edge-splitting and
395*03ce13f7SAndroid Build Coastguard Worker // therefore has 1 in-edge and 1 out-edge (actually, possibly more than 1
396*03ce13f7SAndroid Build Coastguard Worker // in-edge if the predecessor node was contracted). If this changes in
397*03ce13f7SAndroid Build Coastguard Worker // the future, rethink the strategy.
398*03ce13f7SAndroid Build Coastguard Worker assert(Node->getInEdges().size() >= 1);
399*03ce13f7SAndroid Build Coastguard Worker assert(Node->hasSingleOutEdge());
400*03ce13f7SAndroid Build Coastguard Worker
401*03ce13f7SAndroid Build Coastguard Worker // If it's a (non-critical) edge where the successor has a single
402*03ce13f7SAndroid Build Coastguard Worker // in-edge, then place it before the successor.
403*03ce13f7SAndroid Build Coastguard Worker CfgNode *Succ = Node->getOutEdges().front();
404*03ce13f7SAndroid Build Coastguard Worker if (Succ->getInEdges().size() == 1 &&
405*03ce13f7SAndroid Build Coastguard Worker PlaceIndex[Succ->getIndex()] != NoPlace) {
406*03ce13f7SAndroid Build Coastguard Worker Placed.insert(PlaceIndex[Succ->getIndex()], Node);
407*03ce13f7SAndroid Build Coastguard Worker PlaceIndex[Node->getIndex()] = PlaceIndex[Succ->getIndex()];
408*03ce13f7SAndroid Build Coastguard Worker continue;
409*03ce13f7SAndroid Build Coastguard Worker }
410*03ce13f7SAndroid Build Coastguard Worker
411*03ce13f7SAndroid Build Coastguard Worker // Otherwise, place it after the (first) predecessor.
412*03ce13f7SAndroid Build Coastguard Worker CfgNode *Pred = Node->getInEdges().front();
413*03ce13f7SAndroid Build Coastguard Worker auto PredPosition = PlaceIndex[Pred->getIndex()];
414*03ce13f7SAndroid Build Coastguard Worker // It shouldn't be the case that PredPosition==NoPlace, but if that
415*03ce13f7SAndroid Build Coastguard Worker // somehow turns out to be true, we just insert Node before
416*03ce13f7SAndroid Build Coastguard Worker // PredPosition=NoPlace=Placed.end() .
417*03ce13f7SAndroid Build Coastguard Worker if (PredPosition != NoPlace)
418*03ce13f7SAndroid Build Coastguard Worker ++PredPosition;
419*03ce13f7SAndroid Build Coastguard Worker Placed.insert(PredPosition, Node);
420*03ce13f7SAndroid Build Coastguard Worker PlaceIndex[Node->getIndex()] = PredPosition;
421*03ce13f7SAndroid Build Coastguard Worker } while (0);
422*03ce13f7SAndroid Build Coastguard Worker
423*03ce13f7SAndroid Build Coastguard Worker --PlaceIndex[Node->getIndex()];
424*03ce13f7SAndroid Build Coastguard Worker assert(*PlaceIndex[Node->getIndex()] == Node);
425*03ce13f7SAndroid Build Coastguard Worker }
426*03ce13f7SAndroid Build Coastguard Worker
427*03ce13f7SAndroid Build Coastguard Worker // Reorder Nodes according to the built-up lists.
428*03ce13f7SAndroid Build Coastguard Worker NodeList Reordered;
429*03ce13f7SAndroid Build Coastguard Worker Reordered.reserve(Placed.size() + Unreachable.size());
430*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Placed)
431*03ce13f7SAndroid Build Coastguard Worker Reordered.push_back(Node);
432*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Unreachable)
433*03ce13f7SAndroid Build Coastguard Worker Reordered.push_back(Node);
434*03ce13f7SAndroid Build Coastguard Worker assert(getNumNodes() == Reordered.size());
435*03ce13f7SAndroid Build Coastguard Worker swapNodes(Reordered);
436*03ce13f7SAndroid Build Coastguard Worker }
437*03ce13f7SAndroid Build Coastguard Worker
localCSE(bool AssumeSSA)438*03ce13f7SAndroid Build Coastguard Worker void Cfg::localCSE(bool AssumeSSA) {
439*03ce13f7SAndroid Build Coastguard Worker // Performs basic-block local common-subexpression elimination
440*03ce13f7SAndroid Build Coastguard Worker // If we have
441*03ce13f7SAndroid Build Coastguard Worker // t1 = op b c
442*03ce13f7SAndroid Build Coastguard Worker // t2 = op b c
443*03ce13f7SAndroid Build Coastguard Worker // This pass will replace future references to t2 in a basic block by t1
444*03ce13f7SAndroid Build Coastguard Worker // Points to note:
445*03ce13f7SAndroid Build Coastguard Worker // 1. Assumes SSA by default. To change this, use -lcse=no-ssa
446*03ce13f7SAndroid Build Coastguard Worker // This is needed if this pass is moved to a point later in the pipeline.
447*03ce13f7SAndroid Build Coastguard Worker // If variables have a single definition (in the node), CSE can work just
448*03ce13f7SAndroid Build Coastguard Worker // on the basis of an equality compare on instructions (sans Dest). When
449*03ce13f7SAndroid Build Coastguard Worker // variables can be updated (hence, non-SSA) the result of a previous
450*03ce13f7SAndroid Build Coastguard Worker // instruction which used that variable as an operand can not be reused.
451*03ce13f7SAndroid Build Coastguard Worker // 2. Leaves removal of instructions to DCE.
452*03ce13f7SAndroid Build Coastguard Worker // 3. Only enabled on arithmetic instructions. pnacl-clang (-O2) is expected
453*03ce13f7SAndroid Build Coastguard Worker // to take care of cases not arising from GEP simplification.
454*03ce13f7SAndroid Build Coastguard Worker // 4. By default, a single pass is made over each basic block. Control this
455*03ce13f7SAndroid Build Coastguard Worker // with -lcse-max-iters=N
456*03ce13f7SAndroid Build Coastguard Worker
457*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_localCse, this);
458*03ce13f7SAndroid Build Coastguard Worker struct VariableHash {
459*03ce13f7SAndroid Build Coastguard Worker size_t operator()(const Variable *Var) const { return Var->hashValue(); }
460*03ce13f7SAndroid Build Coastguard Worker };
461*03ce13f7SAndroid Build Coastguard Worker
462*03ce13f7SAndroid Build Coastguard Worker struct InstHash {
463*03ce13f7SAndroid Build Coastguard Worker size_t operator()(const Inst *Instr) const {
464*03ce13f7SAndroid Build Coastguard Worker auto Kind = Instr->getKind();
465*03ce13f7SAndroid Build Coastguard Worker auto Result =
466*03ce13f7SAndroid Build Coastguard Worker std::hash<typename std::underlying_type<Inst::InstKind>::type>()(
467*03ce13f7SAndroid Build Coastguard Worker Kind);
468*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < Instr->getSrcSize(); ++i) {
469*03ce13f7SAndroid Build Coastguard Worker Result ^= Instr->getSrc(i)->hashValue();
470*03ce13f7SAndroid Build Coastguard Worker }
471*03ce13f7SAndroid Build Coastguard Worker return Result;
472*03ce13f7SAndroid Build Coastguard Worker }
473*03ce13f7SAndroid Build Coastguard Worker };
474*03ce13f7SAndroid Build Coastguard Worker struct InstEq {
475*03ce13f7SAndroid Build Coastguard Worker bool srcEq(const Operand *A, const Operand *B) const {
476*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Variable>(A) || llvm::isa<Constant>(A))
477*03ce13f7SAndroid Build Coastguard Worker return (A == B);
478*03ce13f7SAndroid Build Coastguard Worker return false;
479*03ce13f7SAndroid Build Coastguard Worker }
480*03ce13f7SAndroid Build Coastguard Worker bool operator()(const Inst *InstrA, const Inst *InstrB) const {
481*03ce13f7SAndroid Build Coastguard Worker if ((InstrA->getKind() != InstrB->getKind()) ||
482*03ce13f7SAndroid Build Coastguard Worker (InstrA->getSrcSize() != InstrB->getSrcSize()))
483*03ce13f7SAndroid Build Coastguard Worker return false;
484*03ce13f7SAndroid Build Coastguard Worker
485*03ce13f7SAndroid Build Coastguard Worker if (auto *A = llvm::dyn_cast<InstArithmetic>(InstrA)) {
486*03ce13f7SAndroid Build Coastguard Worker auto *B = llvm::cast<InstArithmetic>(InstrB);
487*03ce13f7SAndroid Build Coastguard Worker // A, B are guaranteed to be of the same 'kind' at this point
488*03ce13f7SAndroid Build Coastguard Worker // So, dyn_cast is not needed
489*03ce13f7SAndroid Build Coastguard Worker if (A->getOp() != B->getOp())
490*03ce13f7SAndroid Build Coastguard Worker return false;
491*03ce13f7SAndroid Build Coastguard Worker }
492*03ce13f7SAndroid Build Coastguard Worker // Does not enter loop if different kind or number of operands
493*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < InstrA->getSrcSize(); ++i) {
494*03ce13f7SAndroid Build Coastguard Worker if (!srcEq(InstrA->getSrc(i), InstrB->getSrc(i)))
495*03ce13f7SAndroid Build Coastguard Worker return false;
496*03ce13f7SAndroid Build Coastguard Worker }
497*03ce13f7SAndroid Build Coastguard Worker return true;
498*03ce13f7SAndroid Build Coastguard Worker }
499*03ce13f7SAndroid Build Coastguard Worker };
500*03ce13f7SAndroid Build Coastguard Worker
501*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : getNodes()) {
502*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedSet<Inst *, InstHash, InstEq> Seen;
503*03ce13f7SAndroid Build Coastguard Worker // Stores currently available instructions.
504*03ce13f7SAndroid Build Coastguard Worker
505*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedMap<Variable *, Variable *, VariableHash> Replacements;
506*03ce13f7SAndroid Build Coastguard Worker // Combining the above two into a single data structure might consume less
507*03ce13f7SAndroid Build Coastguard Worker // memory but will be slower i.e map of Instruction -> Set of Variables
508*03ce13f7SAndroid Build Coastguard Worker
509*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedMap<Variable *, std::vector<Inst *>, VariableHash> Dependency;
510*03ce13f7SAndroid Build Coastguard Worker // Maps a variable to the Instructions that depend on it.
511*03ce13f7SAndroid Build Coastguard Worker // a = op1 b c
512*03ce13f7SAndroid Build Coastguard Worker // x = op2 c d
513*03ce13f7SAndroid Build Coastguard Worker // Will result in the map : b -> {a}, c -> {a, x}, d -> {x}
514*03ce13f7SAndroid Build Coastguard Worker // Not necessary for SSA as dependencies will never be invalidated, and the
515*03ce13f7SAndroid Build Coastguard Worker // container will use minimal memory when left unused.
516*03ce13f7SAndroid Build Coastguard Worker
517*03ce13f7SAndroid Build Coastguard Worker auto IterCount = getFlags().getLocalCseMaxIterations();
518*03ce13f7SAndroid Build Coastguard Worker
519*03ce13f7SAndroid Build Coastguard Worker for (uint32_t i = 0; i < IterCount; ++i) {
520*03ce13f7SAndroid Build Coastguard Worker // TODO(manasijm): Stats on IterCount -> performance
521*03ce13f7SAndroid Build Coastguard Worker for (Inst &Instr : Node->getInsts()) {
522*03ce13f7SAndroid Build Coastguard Worker if (Instr.isDeleted() || !llvm::isa<InstArithmetic>(&Instr))
523*03ce13f7SAndroid Build Coastguard Worker continue;
524*03ce13f7SAndroid Build Coastguard Worker if (!AssumeSSA) {
525*03ce13f7SAndroid Build Coastguard Worker // Invalidate replacements
526*03ce13f7SAndroid Build Coastguard Worker auto Iter = Replacements.find(Instr.getDest());
527*03ce13f7SAndroid Build Coastguard Worker if (Iter != Replacements.end()) {
528*03ce13f7SAndroid Build Coastguard Worker Replacements.erase(Iter);
529*03ce13f7SAndroid Build Coastguard Worker }
530*03ce13f7SAndroid Build Coastguard Worker
531*03ce13f7SAndroid Build Coastguard Worker // Invalidate 'seen' instructions whose operands were just updated.
532*03ce13f7SAndroid Build Coastguard Worker auto DepIter = Dependency.find(Instr.getDest());
533*03ce13f7SAndroid Build Coastguard Worker if (DepIter != Dependency.end()) {
534*03ce13f7SAndroid Build Coastguard Worker for (auto *DepInst : DepIter->second) {
535*03ce13f7SAndroid Build Coastguard Worker Seen.erase(DepInst);
536*03ce13f7SAndroid Build Coastguard Worker }
537*03ce13f7SAndroid Build Coastguard Worker }
538*03ce13f7SAndroid Build Coastguard Worker }
539*03ce13f7SAndroid Build Coastguard Worker
540*03ce13f7SAndroid Build Coastguard Worker // Replace - doing this before checking for repetitions might enable
541*03ce13f7SAndroid Build Coastguard Worker // more optimizations
542*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < Instr.getSrcSize(); ++i) {
543*03ce13f7SAndroid Build Coastguard Worker auto *Opnd = Instr.getSrc(i);
544*03ce13f7SAndroid Build Coastguard Worker if (auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
545*03ce13f7SAndroid Build Coastguard Worker if (Replacements.find(Var) != Replacements.end()) {
546*03ce13f7SAndroid Build Coastguard Worker Instr.replaceSource(i, Replacements[Var]);
547*03ce13f7SAndroid Build Coastguard Worker }
548*03ce13f7SAndroid Build Coastguard Worker }
549*03ce13f7SAndroid Build Coastguard Worker }
550*03ce13f7SAndroid Build Coastguard Worker
551*03ce13f7SAndroid Build Coastguard Worker // Check for repetitions
552*03ce13f7SAndroid Build Coastguard Worker auto SeenIter = Seen.find(&Instr);
553*03ce13f7SAndroid Build Coastguard Worker if (SeenIter != Seen.end()) { // seen before
554*03ce13f7SAndroid Build Coastguard Worker const Inst *Found = *SeenIter;
555*03ce13f7SAndroid Build Coastguard Worker Replacements[Instr.getDest()] = Found->getDest();
556*03ce13f7SAndroid Build Coastguard Worker } else { // new
557*03ce13f7SAndroid Build Coastguard Worker Seen.insert(&Instr);
558*03ce13f7SAndroid Build Coastguard Worker
559*03ce13f7SAndroid Build Coastguard Worker if (!AssumeSSA) {
560*03ce13f7SAndroid Build Coastguard Worker // Update dependencies
561*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < Instr.getSrcSize(); ++i) {
562*03ce13f7SAndroid Build Coastguard Worker auto *Opnd = Instr.getSrc(i);
563*03ce13f7SAndroid Build Coastguard Worker if (auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
564*03ce13f7SAndroid Build Coastguard Worker Dependency[Var].push_back(&Instr);
565*03ce13f7SAndroid Build Coastguard Worker }
566*03ce13f7SAndroid Build Coastguard Worker }
567*03ce13f7SAndroid Build Coastguard Worker }
568*03ce13f7SAndroid Build Coastguard Worker }
569*03ce13f7SAndroid Build Coastguard Worker }
570*03ce13f7SAndroid Build Coastguard Worker }
571*03ce13f7SAndroid Build Coastguard Worker }
572*03ce13f7SAndroid Build Coastguard Worker }
573*03ce13f7SAndroid Build Coastguard Worker
loopInvariantCodeMotion()574*03ce13f7SAndroid Build Coastguard Worker void Cfg::loopInvariantCodeMotion() {
575*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_loopInvariantCodeMotion, this);
576*03ce13f7SAndroid Build Coastguard Worker // Does not introduce new nodes as of now.
577*03ce13f7SAndroid Build Coastguard Worker for (auto &Loop : LoopInfo) {
578*03ce13f7SAndroid Build Coastguard Worker CfgNode *Header = Loop.Header;
579*03ce13f7SAndroid Build Coastguard Worker assert(Header);
580*03ce13f7SAndroid Build Coastguard Worker if (Header->getLoopNestDepth() < 1)
581*03ce13f7SAndroid Build Coastguard Worker return;
582*03ce13f7SAndroid Build Coastguard Worker CfgNode *PreHeader = Loop.PreHeader;
583*03ce13f7SAndroid Build Coastguard Worker if (PreHeader == nullptr || PreHeader->getInsts().size() == 0) {
584*03ce13f7SAndroid Build Coastguard Worker return; // try next loop
585*03ce13f7SAndroid Build Coastguard Worker }
586*03ce13f7SAndroid Build Coastguard Worker
587*03ce13f7SAndroid Build Coastguard Worker auto &Insts = PreHeader->getInsts();
588*03ce13f7SAndroid Build Coastguard Worker auto &LastInst = Insts.back();
589*03ce13f7SAndroid Build Coastguard Worker Insts.pop_back();
590*03ce13f7SAndroid Build Coastguard Worker
591*03ce13f7SAndroid Build Coastguard Worker for (auto *Inst : findLoopInvariantInstructions(Loop.Body)) {
592*03ce13f7SAndroid Build Coastguard Worker PreHeader->appendInst(Inst);
593*03ce13f7SAndroid Build Coastguard Worker }
594*03ce13f7SAndroid Build Coastguard Worker PreHeader->appendInst(&LastInst);
595*03ce13f7SAndroid Build Coastguard Worker }
596*03ce13f7SAndroid Build Coastguard Worker }
597*03ce13f7SAndroid Build Coastguard Worker
598*03ce13f7SAndroid Build Coastguard Worker CfgVector<Inst *>
findLoopInvariantInstructions(const CfgUnorderedSet<SizeT> & Body)599*03ce13f7SAndroid Build Coastguard Worker Cfg::findLoopInvariantInstructions(const CfgUnorderedSet<SizeT> &Body) {
600*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedSet<Inst *> InvariantInsts;
601*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedSet<Variable *> InvariantVars;
602*03ce13f7SAndroid Build Coastguard Worker for (auto *Var : getArgs()) {
603*03ce13f7SAndroid Build Coastguard Worker InvariantVars.insert(Var);
604*03ce13f7SAndroid Build Coastguard Worker }
605*03ce13f7SAndroid Build Coastguard Worker bool Changed = false;
606*03ce13f7SAndroid Build Coastguard Worker do {
607*03ce13f7SAndroid Build Coastguard Worker Changed = false;
608*03ce13f7SAndroid Build Coastguard Worker for (auto NodeIndex : Body) {
609*03ce13f7SAndroid Build Coastguard Worker auto *Node = Nodes[NodeIndex];
610*03ce13f7SAndroid Build Coastguard Worker CfgVector<std::reference_wrapper<Inst>> Insts(Node->getInsts().begin(),
611*03ce13f7SAndroid Build Coastguard Worker Node->getInsts().end());
612*03ce13f7SAndroid Build Coastguard Worker
613*03ce13f7SAndroid Build Coastguard Worker for (auto &InstRef : Insts) {
614*03ce13f7SAndroid Build Coastguard Worker auto &Inst = InstRef.get();
615*03ce13f7SAndroid Build Coastguard Worker if (Inst.isDeleted() ||
616*03ce13f7SAndroid Build Coastguard Worker InvariantInsts.find(&Inst) != InvariantInsts.end())
617*03ce13f7SAndroid Build Coastguard Worker continue;
618*03ce13f7SAndroid Build Coastguard Worker switch (Inst.getKind()) {
619*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Alloca:
620*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Br:
621*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Ret:
622*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Phi:
623*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Call:
624*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Intrinsic:
625*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Load:
626*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Store:
627*03ce13f7SAndroid Build Coastguard Worker case Inst::InstKind::Switch:
628*03ce13f7SAndroid Build Coastguard Worker continue;
629*03ce13f7SAndroid Build Coastguard Worker default:
630*03ce13f7SAndroid Build Coastguard Worker break;
631*03ce13f7SAndroid Build Coastguard Worker }
632*03ce13f7SAndroid Build Coastguard Worker
633*03ce13f7SAndroid Build Coastguard Worker bool IsInvariant = true;
634*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < Inst.getSrcSize(); ++i) {
635*03ce13f7SAndroid Build Coastguard Worker if (auto *Var = llvm::dyn_cast<Variable>(Inst.getSrc(i))) {
636*03ce13f7SAndroid Build Coastguard Worker if (InvariantVars.find(Var) == InvariantVars.end()) {
637*03ce13f7SAndroid Build Coastguard Worker IsInvariant = false;
638*03ce13f7SAndroid Build Coastguard Worker }
639*03ce13f7SAndroid Build Coastguard Worker }
640*03ce13f7SAndroid Build Coastguard Worker }
641*03ce13f7SAndroid Build Coastguard Worker if (IsInvariant) {
642*03ce13f7SAndroid Build Coastguard Worker Changed = true;
643*03ce13f7SAndroid Build Coastguard Worker InvariantInsts.insert(&Inst);
644*03ce13f7SAndroid Build Coastguard Worker Node->getInsts().remove(Inst);
645*03ce13f7SAndroid Build Coastguard Worker if (Inst.getDest() != nullptr) {
646*03ce13f7SAndroid Build Coastguard Worker InvariantVars.insert(Inst.getDest());
647*03ce13f7SAndroid Build Coastguard Worker }
648*03ce13f7SAndroid Build Coastguard Worker }
649*03ce13f7SAndroid Build Coastguard Worker }
650*03ce13f7SAndroid Build Coastguard Worker }
651*03ce13f7SAndroid Build Coastguard Worker } while (Changed);
652*03ce13f7SAndroid Build Coastguard Worker
653*03ce13f7SAndroid Build Coastguard Worker CfgVector<Inst *> InstVector(InvariantInsts.begin(), InvariantInsts.end());
654*03ce13f7SAndroid Build Coastguard Worker std::sort(InstVector.begin(), InstVector.end(),
655*03ce13f7SAndroid Build Coastguard Worker [](Inst *A, Inst *B) { return A->getNumber() < B->getNumber(); });
656*03ce13f7SAndroid Build Coastguard Worker return InstVector;
657*03ce13f7SAndroid Build Coastguard Worker }
658*03ce13f7SAndroid Build Coastguard Worker
shortCircuitJumps()659*03ce13f7SAndroid Build Coastguard Worker void Cfg::shortCircuitJumps() {
660*03ce13f7SAndroid Build Coastguard Worker // Split Nodes whenever an early jump is possible.
661*03ce13f7SAndroid Build Coastguard Worker // __N :
662*03ce13f7SAndroid Build Coastguard Worker // a = <something>
663*03ce13f7SAndroid Build Coastguard Worker // Instruction 1 without side effect
664*03ce13f7SAndroid Build Coastguard Worker // ... b = <something> ...
665*03ce13f7SAndroid Build Coastguard Worker // Instruction N without side effect
666*03ce13f7SAndroid Build Coastguard Worker // t1 = or a b
667*03ce13f7SAndroid Build Coastguard Worker // br t1 __X __Y
668*03ce13f7SAndroid Build Coastguard Worker //
669*03ce13f7SAndroid Build Coastguard Worker // is transformed into:
670*03ce13f7SAndroid Build Coastguard Worker // __N :
671*03ce13f7SAndroid Build Coastguard Worker // a = <something>
672*03ce13f7SAndroid Build Coastguard Worker // br a __X __N_ext
673*03ce13f7SAndroid Build Coastguard Worker //
674*03ce13f7SAndroid Build Coastguard Worker // __N_ext :
675*03ce13f7SAndroid Build Coastguard Worker // Instruction 1 without side effect
676*03ce13f7SAndroid Build Coastguard Worker // ... b = <something> ...
677*03ce13f7SAndroid Build Coastguard Worker // Instruction N without side effect
678*03ce13f7SAndroid Build Coastguard Worker // br b __X __Y
679*03ce13f7SAndroid Build Coastguard Worker // (Similar logic for AND, jump to false instead of true target.)
680*03ce13f7SAndroid Build Coastguard Worker
681*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_shortCircuit, this);
682*03ce13f7SAndroid Build Coastguard Worker getVMetadata()->init(VMK_Uses);
683*03ce13f7SAndroid Build Coastguard Worker auto NodeStack = this->getNodes();
684*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedMap<SizeT, CfgVector<CfgNode *>> Splits;
685*03ce13f7SAndroid Build Coastguard Worker while (!NodeStack.empty()) {
686*03ce13f7SAndroid Build Coastguard Worker auto *Node = NodeStack.back();
687*03ce13f7SAndroid Build Coastguard Worker NodeStack.pop_back();
688*03ce13f7SAndroid Build Coastguard Worker auto NewNode = Node->shortCircuit();
689*03ce13f7SAndroid Build Coastguard Worker if (NewNode) {
690*03ce13f7SAndroid Build Coastguard Worker NodeStack.push_back(NewNode);
691*03ce13f7SAndroid Build Coastguard Worker NodeStack.push_back(Node);
692*03ce13f7SAndroid Build Coastguard Worker Splits[Node->getIndex()].push_back(NewNode);
693*03ce13f7SAndroid Build Coastguard Worker }
694*03ce13f7SAndroid Build Coastguard Worker }
695*03ce13f7SAndroid Build Coastguard Worker
696*03ce13f7SAndroid Build Coastguard Worker // Insert nodes in the right place
697*03ce13f7SAndroid Build Coastguard Worker NodeList NewList;
698*03ce13f7SAndroid Build Coastguard Worker NewList.reserve(Nodes.size());
699*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedSet<SizeT> Inserted;
700*03ce13f7SAndroid Build Coastguard Worker for (auto *Node : Nodes) {
701*03ce13f7SAndroid Build Coastguard Worker if (Inserted.find(Node->getIndex()) != Inserted.end())
702*03ce13f7SAndroid Build Coastguard Worker continue; // already inserted
703*03ce13f7SAndroid Build Coastguard Worker NodeList Stack{Node};
704*03ce13f7SAndroid Build Coastguard Worker while (!Stack.empty()) {
705*03ce13f7SAndroid Build Coastguard Worker auto *Current = Stack.back();
706*03ce13f7SAndroid Build Coastguard Worker Stack.pop_back();
707*03ce13f7SAndroid Build Coastguard Worker Inserted.insert(Current->getIndex());
708*03ce13f7SAndroid Build Coastguard Worker NewList.push_back(Current);
709*03ce13f7SAndroid Build Coastguard Worker for (auto *Next : Splits[Current->getIndex()]) {
710*03ce13f7SAndroid Build Coastguard Worker Stack.push_back(Next);
711*03ce13f7SAndroid Build Coastguard Worker }
712*03ce13f7SAndroid Build Coastguard Worker }
713*03ce13f7SAndroid Build Coastguard Worker }
714*03ce13f7SAndroid Build Coastguard Worker
715*03ce13f7SAndroid Build Coastguard Worker SizeT NodeIndex = 0;
716*03ce13f7SAndroid Build Coastguard Worker for (auto *Node : NewList) {
717*03ce13f7SAndroid Build Coastguard Worker Node->resetIndex(NodeIndex++);
718*03ce13f7SAndroid Build Coastguard Worker }
719*03ce13f7SAndroid Build Coastguard Worker Nodes = NewList;
720*03ce13f7SAndroid Build Coastguard Worker }
721*03ce13f7SAndroid Build Coastguard Worker
floatConstantCSE()722*03ce13f7SAndroid Build Coastguard Worker void Cfg::floatConstantCSE() {
723*03ce13f7SAndroid Build Coastguard Worker // Load multiple uses of a floating point constant (between two call
724*03ce13f7SAndroid Build Coastguard Worker // instructions or block start/end) into a variable before its first use.
725*03ce13f7SAndroid Build Coastguard Worker // t1 = b + 1.0
726*03ce13f7SAndroid Build Coastguard Worker // t2 = c + 1.0
727*03ce13f7SAndroid Build Coastguard Worker // Gets transformed to:
728*03ce13f7SAndroid Build Coastguard Worker // t0 = 1.0
729*03ce13f7SAndroid Build Coastguard Worker // t0_1 = t0
730*03ce13f7SAndroid Build Coastguard Worker // t1 = b + t0_1
731*03ce13f7SAndroid Build Coastguard Worker // t2 = c + t0_1
732*03ce13f7SAndroid Build Coastguard Worker // Call instructions reset the procedure, but use the same variable, just in
733*03ce13f7SAndroid Build Coastguard Worker // case it got a register. We are assuming floating point registers are not
734*03ce13f7SAndroid Build Coastguard Worker // callee saved in general. Example, continuing from before:
735*03ce13f7SAndroid Build Coastguard Worker // result = call <some function>
736*03ce13f7SAndroid Build Coastguard Worker // t3 = d + 1.0
737*03ce13f7SAndroid Build Coastguard Worker // Gets transformed to:
738*03ce13f7SAndroid Build Coastguard Worker // result = call <some function>
739*03ce13f7SAndroid Build Coastguard Worker // t0_2 = t0
740*03ce13f7SAndroid Build Coastguard Worker // t3 = d + t0_2
741*03ce13f7SAndroid Build Coastguard Worker // TODO(manasijm, stichnot): Figure out how to 'link' t0 to the stack slot of
742*03ce13f7SAndroid Build Coastguard Worker // 1.0. When t0 does not get a register, introducing an extra assignment
743*03ce13f7SAndroid Build Coastguard Worker // statement does not make sense. The relevant portion is marked below.
744*03ce13f7SAndroid Build Coastguard Worker
745*03ce13f7SAndroid Build Coastguard Worker TimerMarker _(TimerStack::TT_floatConstantCse, this);
746*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : getNodes()) {
747*03ce13f7SAndroid Build Coastguard Worker
748*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedMap<Constant *, Variable *> ConstCache;
749*03ce13f7SAndroid Build Coastguard Worker auto Current = Node->getInsts().begin();
750*03ce13f7SAndroid Build Coastguard Worker auto End = Node->getInsts().end();
751*03ce13f7SAndroid Build Coastguard Worker while (Current != End) {
752*03ce13f7SAndroid Build Coastguard Worker CfgUnorderedMap<Constant *, CfgVector<InstList::iterator>> FloatUses;
753*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<InstCall>(iteratorToInst(Current))) {
754*03ce13f7SAndroid Build Coastguard Worker ++Current;
755*03ce13f7SAndroid Build Coastguard Worker assert(Current != End);
756*03ce13f7SAndroid Build Coastguard Worker // Block should not end with a call
757*03ce13f7SAndroid Build Coastguard Worker }
758*03ce13f7SAndroid Build Coastguard Worker while (Current != End && !llvm::isa<InstCall>(iteratorToInst(Current))) {
759*03ce13f7SAndroid Build Coastguard Worker if (!Current->isDeleted()) {
760*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < Current->getSrcSize(); ++i) {
761*03ce13f7SAndroid Build Coastguard Worker if (auto *Const = llvm::dyn_cast<Constant>(Current->getSrc(i))) {
762*03ce13f7SAndroid Build Coastguard Worker if (Const->getType() == IceType_f32 ||
763*03ce13f7SAndroid Build Coastguard Worker Const->getType() == IceType_f64) {
764*03ce13f7SAndroid Build Coastguard Worker FloatUses[Const].push_back(Current);
765*03ce13f7SAndroid Build Coastguard Worker }
766*03ce13f7SAndroid Build Coastguard Worker }
767*03ce13f7SAndroid Build Coastguard Worker }
768*03ce13f7SAndroid Build Coastguard Worker }
769*03ce13f7SAndroid Build Coastguard Worker ++Current;
770*03ce13f7SAndroid Build Coastguard Worker }
771*03ce13f7SAndroid Build Coastguard Worker for (auto &Pair : FloatUses) {
772*03ce13f7SAndroid Build Coastguard Worker static constexpr SizeT MinUseThreshold = 3;
773*03ce13f7SAndroid Build Coastguard Worker if (Pair.second.size() < MinUseThreshold)
774*03ce13f7SAndroid Build Coastguard Worker continue;
775*03ce13f7SAndroid Build Coastguard Worker // Only consider constants with at least `MinUseThreshold` uses
776*03ce13f7SAndroid Build Coastguard Worker auto &Insts = Node->getInsts();
777*03ce13f7SAndroid Build Coastguard Worker
778*03ce13f7SAndroid Build Coastguard Worker if (ConstCache.find(Pair.first) == ConstCache.end()) {
779*03ce13f7SAndroid Build Coastguard Worker // Saw a constant (which is used at least twice) for the first time
780*03ce13f7SAndroid Build Coastguard Worker auto *NewVar = makeVariable(Pair.first->getType());
781*03ce13f7SAndroid Build Coastguard Worker // NewVar->setLinkedTo(Pair.first);
782*03ce13f7SAndroid Build Coastguard Worker // TODO(manasijm): Plumbing for linking to an Operand.
783*03ce13f7SAndroid Build Coastguard Worker auto *Assign = InstAssign::create(Node->getCfg(), NewVar, Pair.first);
784*03ce13f7SAndroid Build Coastguard Worker Insts.insert(Pair.second[0], Assign);
785*03ce13f7SAndroid Build Coastguard Worker ConstCache[Pair.first] = NewVar;
786*03ce13f7SAndroid Build Coastguard Worker }
787*03ce13f7SAndroid Build Coastguard Worker
788*03ce13f7SAndroid Build Coastguard Worker auto *NewVar = makeVariable(Pair.first->getType());
789*03ce13f7SAndroid Build Coastguard Worker NewVar->setLinkedTo(ConstCache[Pair.first]);
790*03ce13f7SAndroid Build Coastguard Worker auto *Assign =
791*03ce13f7SAndroid Build Coastguard Worker InstAssign::create(Node->getCfg(), NewVar, ConstCache[Pair.first]);
792*03ce13f7SAndroid Build Coastguard Worker
793*03ce13f7SAndroid Build Coastguard Worker Insts.insert(Pair.second[0], Assign);
794*03ce13f7SAndroid Build Coastguard Worker for (auto InstUse : Pair.second) {
795*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < InstUse->getSrcSize(); ++i) {
796*03ce13f7SAndroid Build Coastguard Worker if (auto *Const = llvm::dyn_cast<Constant>(InstUse->getSrc(i))) {
797*03ce13f7SAndroid Build Coastguard Worker if (Const == Pair.first) {
798*03ce13f7SAndroid Build Coastguard Worker InstUse->replaceSource(i, NewVar);
799*03ce13f7SAndroid Build Coastguard Worker }
800*03ce13f7SAndroid Build Coastguard Worker }
801*03ce13f7SAndroid Build Coastguard Worker }
802*03ce13f7SAndroid Build Coastguard Worker }
803*03ce13f7SAndroid Build Coastguard Worker }
804*03ce13f7SAndroid Build Coastguard Worker }
805*03ce13f7SAndroid Build Coastguard Worker }
806*03ce13f7SAndroid Build Coastguard Worker }
807*03ce13f7SAndroid Build Coastguard Worker
doArgLowering()808*03ce13f7SAndroid Build Coastguard Worker void Cfg::doArgLowering() {
809*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_doArgLowering, this);
810*03ce13f7SAndroid Build Coastguard Worker getTarget()->lowerArguments();
811*03ce13f7SAndroid Build Coastguard Worker }
812*03ce13f7SAndroid Build Coastguard Worker
sortAndCombineAllocas(CfgVector<InstAlloca * > & Allocas,uint32_t CombinedAlignment,InstList & Insts,AllocaBaseVariableType BaseVariableType)813*03ce13f7SAndroid Build Coastguard Worker void Cfg::sortAndCombineAllocas(CfgVector<InstAlloca *> &Allocas,
814*03ce13f7SAndroid Build Coastguard Worker uint32_t CombinedAlignment, InstList &Insts,
815*03ce13f7SAndroid Build Coastguard Worker AllocaBaseVariableType BaseVariableType) {
816*03ce13f7SAndroid Build Coastguard Worker if (Allocas.empty())
817*03ce13f7SAndroid Build Coastguard Worker return;
818*03ce13f7SAndroid Build Coastguard Worker // Sort by decreasing alignment.
819*03ce13f7SAndroid Build Coastguard Worker std::sort(Allocas.begin(), Allocas.end(), [](InstAlloca *A1, InstAlloca *A2) {
820*03ce13f7SAndroid Build Coastguard Worker uint32_t Align1 = A1->getAlignInBytes();
821*03ce13f7SAndroid Build Coastguard Worker uint32_t Align2 = A2->getAlignInBytes();
822*03ce13f7SAndroid Build Coastguard Worker if (Align1 == Align2)
823*03ce13f7SAndroid Build Coastguard Worker return A1->getNumber() < A2->getNumber();
824*03ce13f7SAndroid Build Coastguard Worker else
825*03ce13f7SAndroid Build Coastguard Worker return Align1 > Align2;
826*03ce13f7SAndroid Build Coastguard Worker });
827*03ce13f7SAndroid Build Coastguard Worker // Process the allocas in order of decreasing stack alignment. This allows
828*03ce13f7SAndroid Build Coastguard Worker // us to pack less-aligned pieces after more-aligned ones, resulting in less
829*03ce13f7SAndroid Build Coastguard Worker // stack growth. It also allows there to be at most one stack alignment "and"
830*03ce13f7SAndroid Build Coastguard Worker // instruction for a whole list of allocas.
831*03ce13f7SAndroid Build Coastguard Worker uint32_t CurrentOffset = 0;
832*03ce13f7SAndroid Build Coastguard Worker CfgVector<int32_t> Offsets;
833*03ce13f7SAndroid Build Coastguard Worker for (Inst *Instr : Allocas) {
834*03ce13f7SAndroid Build Coastguard Worker auto *Alloca = llvm::cast<InstAlloca>(Instr);
835*03ce13f7SAndroid Build Coastguard Worker // Adjust the size of the allocation up to the next multiple of the
836*03ce13f7SAndroid Build Coastguard Worker // object's alignment.
837*03ce13f7SAndroid Build Coastguard Worker uint32_t Alignment = std::max(Alloca->getAlignInBytes(), 1u);
838*03ce13f7SAndroid Build Coastguard Worker auto *ConstSize =
839*03ce13f7SAndroid Build Coastguard Worker llvm::dyn_cast<ConstantInteger32>(Alloca->getSizeInBytes());
840*03ce13f7SAndroid Build Coastguard Worker const uint32_t Size =
841*03ce13f7SAndroid Build Coastguard Worker Utils::applyAlignment(ConstSize->getValue(), Alignment);
842*03ce13f7SAndroid Build Coastguard Worker
843*03ce13f7SAndroid Build Coastguard Worker // Ensure that the Size does not exceed StackSizeLimit which can lead to
844*03ce13f7SAndroid Build Coastguard Worker // undefined behavior below.
845*03ce13f7SAndroid Build Coastguard Worker if (Size > StackSizeLimit) {
846*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Local variable exceeds stack size limit");
847*03ce13f7SAndroid Build Coastguard Worker return; // NOTREACHED
848*03ce13f7SAndroid Build Coastguard Worker }
849*03ce13f7SAndroid Build Coastguard Worker
850*03ce13f7SAndroid Build Coastguard Worker if (BaseVariableType == BVT_FramePointer) {
851*03ce13f7SAndroid Build Coastguard Worker // Addressing is relative to the frame pointer. Subtract the offset after
852*03ce13f7SAndroid Build Coastguard Worker // adding the size of the alloca, because it grows downwards from the
853*03ce13f7SAndroid Build Coastguard Worker // frame pointer.
854*03ce13f7SAndroid Build Coastguard Worker Offsets.push_back(Target->getFramePointerOffset(CurrentOffset, Size));
855*03ce13f7SAndroid Build Coastguard Worker } else {
856*03ce13f7SAndroid Build Coastguard Worker // Addressing is relative to the stack pointer or to a user pointer. Add
857*03ce13f7SAndroid Build Coastguard Worker // the offset before adding the size of the object, because it grows
858*03ce13f7SAndroid Build Coastguard Worker // upwards from the stack pointer. In addition, if the addressing is
859*03ce13f7SAndroid Build Coastguard Worker // relative to the stack pointer, we need to add the pre-computed max out
860*03ce13f7SAndroid Build Coastguard Worker // args size bytes.
861*03ce13f7SAndroid Build Coastguard Worker const uint32_t OutArgsOffsetOrZero =
862*03ce13f7SAndroid Build Coastguard Worker (BaseVariableType == BVT_StackPointer)
863*03ce13f7SAndroid Build Coastguard Worker ? getTarget()->maxOutArgsSizeBytes()
864*03ce13f7SAndroid Build Coastguard Worker : 0;
865*03ce13f7SAndroid Build Coastguard Worker Offsets.push_back(CurrentOffset + OutArgsOffsetOrZero);
866*03ce13f7SAndroid Build Coastguard Worker }
867*03ce13f7SAndroid Build Coastguard Worker
868*03ce13f7SAndroid Build Coastguard Worker // Ensure that the addition below does not overflow or exceed
869*03ce13f7SAndroid Build Coastguard Worker // StackSizeLimit as this leads to undefined behavior.
870*03ce13f7SAndroid Build Coastguard Worker if (CurrentOffset + Size > StackSizeLimit) {
871*03ce13f7SAndroid Build Coastguard Worker llvm::report_fatal_error("Local variable exceeds stack size limit");
872*03ce13f7SAndroid Build Coastguard Worker return; // NOTREACHED
873*03ce13f7SAndroid Build Coastguard Worker }
874*03ce13f7SAndroid Build Coastguard Worker
875*03ce13f7SAndroid Build Coastguard Worker // Update the running offset of the fused alloca region.
876*03ce13f7SAndroid Build Coastguard Worker CurrentOffset += Size;
877*03ce13f7SAndroid Build Coastguard Worker }
878*03ce13f7SAndroid Build Coastguard Worker // Round the offset up to the alignment granularity to use as the size.
879*03ce13f7SAndroid Build Coastguard Worker uint32_t TotalSize = Utils::applyAlignment(CurrentOffset, CombinedAlignment);
880*03ce13f7SAndroid Build Coastguard Worker // Ensure every alloca was assigned an offset.
881*03ce13f7SAndroid Build Coastguard Worker assert(Allocas.size() == Offsets.size());
882*03ce13f7SAndroid Build Coastguard Worker
883*03ce13f7SAndroid Build Coastguard Worker switch (BaseVariableType) {
884*03ce13f7SAndroid Build Coastguard Worker case BVT_UserPointer: {
885*03ce13f7SAndroid Build Coastguard Worker Variable *BaseVariable = makeVariable(IceType_i32);
886*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < Allocas.size(); ++i) {
887*03ce13f7SAndroid Build Coastguard Worker auto *Alloca = llvm::cast<InstAlloca>(Allocas[i]);
888*03ce13f7SAndroid Build Coastguard Worker // Emit a new addition operation to replace the alloca.
889*03ce13f7SAndroid Build Coastguard Worker Operand *AllocaOffset = Ctx->getConstantInt32(Offsets[i]);
890*03ce13f7SAndroid Build Coastguard Worker InstArithmetic *Add =
891*03ce13f7SAndroid Build Coastguard Worker InstArithmetic::create(this, InstArithmetic::Add, Alloca->getDest(),
892*03ce13f7SAndroid Build Coastguard Worker BaseVariable, AllocaOffset);
893*03ce13f7SAndroid Build Coastguard Worker Insts.push_front(Add);
894*03ce13f7SAndroid Build Coastguard Worker Alloca->setDeleted();
895*03ce13f7SAndroid Build Coastguard Worker }
896*03ce13f7SAndroid Build Coastguard Worker Operand *AllocaSize = Ctx->getConstantInt32(TotalSize);
897*03ce13f7SAndroid Build Coastguard Worker InstAlloca *CombinedAlloca =
898*03ce13f7SAndroid Build Coastguard Worker InstAlloca::create(this, BaseVariable, AllocaSize, CombinedAlignment);
899*03ce13f7SAndroid Build Coastguard Worker CombinedAlloca->setKnownFrameOffset();
900*03ce13f7SAndroid Build Coastguard Worker Insts.push_front(CombinedAlloca);
901*03ce13f7SAndroid Build Coastguard Worker } break;
902*03ce13f7SAndroid Build Coastguard Worker case BVT_StackPointer:
903*03ce13f7SAndroid Build Coastguard Worker case BVT_FramePointer: {
904*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < Allocas.size(); ++i) {
905*03ce13f7SAndroid Build Coastguard Worker auto *Alloca = llvm::cast<InstAlloca>(Allocas[i]);
906*03ce13f7SAndroid Build Coastguard Worker // Emit a fake definition of the rematerializable variable.
907*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Alloca->getDest();
908*03ce13f7SAndroid Build Coastguard Worker auto *Def = InstFakeDef::create(this, Dest);
909*03ce13f7SAndroid Build Coastguard Worker if (BaseVariableType == BVT_StackPointer)
910*03ce13f7SAndroid Build Coastguard Worker Dest->setRematerializable(getTarget()->getStackReg(), Offsets[i]);
911*03ce13f7SAndroid Build Coastguard Worker else
912*03ce13f7SAndroid Build Coastguard Worker Dest->setRematerializable(getTarget()->getFrameReg(), Offsets[i]);
913*03ce13f7SAndroid Build Coastguard Worker Insts.push_front(Def);
914*03ce13f7SAndroid Build Coastguard Worker Alloca->setDeleted();
915*03ce13f7SAndroid Build Coastguard Worker }
916*03ce13f7SAndroid Build Coastguard Worker // Allocate the fixed area in the function prolog.
917*03ce13f7SAndroid Build Coastguard Worker getTarget()->reserveFixedAllocaArea(TotalSize, CombinedAlignment);
918*03ce13f7SAndroid Build Coastguard Worker } break;
919*03ce13f7SAndroid Build Coastguard Worker }
920*03ce13f7SAndroid Build Coastguard Worker }
921*03ce13f7SAndroid Build Coastguard Worker
processAllocas(bool SortAndCombine)922*03ce13f7SAndroid Build Coastguard Worker void Cfg::processAllocas(bool SortAndCombine) {
923*03ce13f7SAndroid Build Coastguard Worker TimerMarker _(TimerStack::TT_alloca, this);
924*03ce13f7SAndroid Build Coastguard Worker const uint32_t StackAlignment = getTarget()->getStackAlignment();
925*03ce13f7SAndroid Build Coastguard Worker CfgNode *EntryNode = getEntryNode();
926*03ce13f7SAndroid Build Coastguard Worker assert(EntryNode);
927*03ce13f7SAndroid Build Coastguard Worker // LLVM enforces power of 2 alignment.
928*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isPowerOf2_32(StackAlignment));
929*03ce13f7SAndroid Build Coastguard Worker // If the ABI's stack alignment is smaller than the vector size (16 bytes),
930*03ce13f7SAndroid Build Coastguard Worker // conservatively use a frame pointer to allow for explicit alignment of the
931*03ce13f7SAndroid Build Coastguard Worker // stack pointer. This needs to happen before register allocation so the frame
932*03ce13f7SAndroid Build Coastguard Worker // pointer can be reserved.
933*03ce13f7SAndroid Build Coastguard Worker if (getTarget()->needsStackPointerAlignment()) {
934*03ce13f7SAndroid Build Coastguard Worker getTarget()->setHasFramePointer();
935*03ce13f7SAndroid Build Coastguard Worker }
936*03ce13f7SAndroid Build Coastguard Worker // Determine if there are large alignment allocations in the entry block or
937*03ce13f7SAndroid Build Coastguard Worker // dynamic allocations (variable size in the entry block).
938*03ce13f7SAndroid Build Coastguard Worker bool HasLargeAlignment = false;
939*03ce13f7SAndroid Build Coastguard Worker bool HasDynamicAllocation = false;
940*03ce13f7SAndroid Build Coastguard Worker for (Inst &Instr : EntryNode->getInsts()) {
941*03ce13f7SAndroid Build Coastguard Worker if (Instr.isDeleted())
942*03ce13f7SAndroid Build Coastguard Worker continue;
943*03ce13f7SAndroid Build Coastguard Worker if (auto *Alloca = llvm::dyn_cast<InstAlloca>(&Instr)) {
944*03ce13f7SAndroid Build Coastguard Worker uint32_t AlignmentParam = Alloca->getAlignInBytes();
945*03ce13f7SAndroid Build Coastguard Worker if (AlignmentParam > StackAlignment)
946*03ce13f7SAndroid Build Coastguard Worker HasLargeAlignment = true;
947*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<Constant>(Alloca->getSizeInBytes()))
948*03ce13f7SAndroid Build Coastguard Worker Alloca->setKnownFrameOffset();
949*03ce13f7SAndroid Build Coastguard Worker else {
950*03ce13f7SAndroid Build Coastguard Worker HasDynamicAllocation = true;
951*03ce13f7SAndroid Build Coastguard Worker // If Allocas are not sorted, the first dynamic allocation causes
952*03ce13f7SAndroid Build Coastguard Worker // later Allocas to be at unknown offsets relative to the stack/frame.
953*03ce13f7SAndroid Build Coastguard Worker if (!SortAndCombine)
954*03ce13f7SAndroid Build Coastguard Worker break;
955*03ce13f7SAndroid Build Coastguard Worker }
956*03ce13f7SAndroid Build Coastguard Worker }
957*03ce13f7SAndroid Build Coastguard Worker }
958*03ce13f7SAndroid Build Coastguard Worker // Don't do the heavyweight sorting and layout for low optimization levels.
959*03ce13f7SAndroid Build Coastguard Worker if (!SortAndCombine)
960*03ce13f7SAndroid Build Coastguard Worker return;
961*03ce13f7SAndroid Build Coastguard Worker // Any alloca outside the entry block is a dynamic allocation.
962*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
963*03ce13f7SAndroid Build Coastguard Worker if (Node == EntryNode)
964*03ce13f7SAndroid Build Coastguard Worker continue;
965*03ce13f7SAndroid Build Coastguard Worker for (Inst &Instr : Node->getInsts()) {
966*03ce13f7SAndroid Build Coastguard Worker if (Instr.isDeleted())
967*03ce13f7SAndroid Build Coastguard Worker continue;
968*03ce13f7SAndroid Build Coastguard Worker if (llvm::isa<InstAlloca>(&Instr)) {
969*03ce13f7SAndroid Build Coastguard Worker // Allocations outside the entry block require a frame pointer.
970*03ce13f7SAndroid Build Coastguard Worker HasDynamicAllocation = true;
971*03ce13f7SAndroid Build Coastguard Worker break;
972*03ce13f7SAndroid Build Coastguard Worker }
973*03ce13f7SAndroid Build Coastguard Worker }
974*03ce13f7SAndroid Build Coastguard Worker if (HasDynamicAllocation)
975*03ce13f7SAndroid Build Coastguard Worker break;
976*03ce13f7SAndroid Build Coastguard Worker }
977*03ce13f7SAndroid Build Coastguard Worker // Mark the target as requiring a frame pointer.
978*03ce13f7SAndroid Build Coastguard Worker if (HasLargeAlignment || HasDynamicAllocation)
979*03ce13f7SAndroid Build Coastguard Worker getTarget()->setHasFramePointer();
980*03ce13f7SAndroid Build Coastguard Worker // Collect the Allocas into the two vectors.
981*03ce13f7SAndroid Build Coastguard Worker // Allocas in the entry block that have constant size and alignment less
982*03ce13f7SAndroid Build Coastguard Worker // than or equal to the function's stack alignment.
983*03ce13f7SAndroid Build Coastguard Worker CfgVector<InstAlloca *> FixedAllocas;
984*03ce13f7SAndroid Build Coastguard Worker // Allocas in the entry block that have constant size and alignment greater
985*03ce13f7SAndroid Build Coastguard Worker // than the function's stack alignment.
986*03ce13f7SAndroid Build Coastguard Worker CfgVector<InstAlloca *> AlignedAllocas;
987*03ce13f7SAndroid Build Coastguard Worker // Maximum alignment used by any alloca.
988*03ce13f7SAndroid Build Coastguard Worker uint32_t MaxAlignment = StackAlignment;
989*03ce13f7SAndroid Build Coastguard Worker for (Inst &Instr : EntryNode->getInsts()) {
990*03ce13f7SAndroid Build Coastguard Worker if (Instr.isDeleted())
991*03ce13f7SAndroid Build Coastguard Worker continue;
992*03ce13f7SAndroid Build Coastguard Worker if (auto *Alloca = llvm::dyn_cast<InstAlloca>(&Instr)) {
993*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<Constant>(Alloca->getSizeInBytes()))
994*03ce13f7SAndroid Build Coastguard Worker continue;
995*03ce13f7SAndroid Build Coastguard Worker uint32_t AlignmentParam = Alloca->getAlignInBytes();
996*03ce13f7SAndroid Build Coastguard Worker // For default align=0, set it to the real value 1, to avoid any
997*03ce13f7SAndroid Build Coastguard Worker // bit-manipulation problems below.
998*03ce13f7SAndroid Build Coastguard Worker AlignmentParam = std::max(AlignmentParam, 1u);
999*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isPowerOf2_32(AlignmentParam));
1000*03ce13f7SAndroid Build Coastguard Worker if (HasDynamicAllocation && AlignmentParam > StackAlignment) {
1001*03ce13f7SAndroid Build Coastguard Worker // If we have both dynamic allocations and large stack alignments,
1002*03ce13f7SAndroid Build Coastguard Worker // high-alignment allocations are pulled out with their own base.
1003*03ce13f7SAndroid Build Coastguard Worker AlignedAllocas.push_back(Alloca);
1004*03ce13f7SAndroid Build Coastguard Worker } else {
1005*03ce13f7SAndroid Build Coastguard Worker FixedAllocas.push_back(Alloca);
1006*03ce13f7SAndroid Build Coastguard Worker }
1007*03ce13f7SAndroid Build Coastguard Worker MaxAlignment = std::max(AlignmentParam, MaxAlignment);
1008*03ce13f7SAndroid Build Coastguard Worker }
1009*03ce13f7SAndroid Build Coastguard Worker }
1010*03ce13f7SAndroid Build Coastguard Worker // Add instructions to the head of the entry block in reverse order.
1011*03ce13f7SAndroid Build Coastguard Worker InstList &Insts = getEntryNode()->getInsts();
1012*03ce13f7SAndroid Build Coastguard Worker if (HasDynamicAllocation && HasLargeAlignment) {
1013*03ce13f7SAndroid Build Coastguard Worker // We are using a frame pointer, but fixed large-alignment alloca addresses
1014*03ce13f7SAndroid Build Coastguard Worker // do not have a known offset from either the stack or frame pointer.
1015*03ce13f7SAndroid Build Coastguard Worker // They grow up from a user pointer from an alloca.
1016*03ce13f7SAndroid Build Coastguard Worker sortAndCombineAllocas(AlignedAllocas, MaxAlignment, Insts, BVT_UserPointer);
1017*03ce13f7SAndroid Build Coastguard Worker // Fixed size allocas are addressed relative to the frame pointer.
1018*03ce13f7SAndroid Build Coastguard Worker sortAndCombineAllocas(FixedAllocas, StackAlignment, Insts,
1019*03ce13f7SAndroid Build Coastguard Worker BVT_FramePointer);
1020*03ce13f7SAndroid Build Coastguard Worker } else {
1021*03ce13f7SAndroid Build Coastguard Worker // Otherwise, fixed size allocas are addressed relative to the stack unless
1022*03ce13f7SAndroid Build Coastguard Worker // there are dynamic allocas.
1023*03ce13f7SAndroid Build Coastguard Worker const AllocaBaseVariableType BasePointerType =
1024*03ce13f7SAndroid Build Coastguard Worker (HasDynamicAllocation ? BVT_FramePointer : BVT_StackPointer);
1025*03ce13f7SAndroid Build Coastguard Worker sortAndCombineAllocas(FixedAllocas, MaxAlignment, Insts, BasePointerType);
1026*03ce13f7SAndroid Build Coastguard Worker }
1027*03ce13f7SAndroid Build Coastguard Worker if (!FixedAllocas.empty() || !AlignedAllocas.empty())
1028*03ce13f7SAndroid Build Coastguard Worker // No use calling findRematerializable() unless there is some
1029*03ce13f7SAndroid Build Coastguard Worker // rematerializable alloca instruction to seed it.
1030*03ce13f7SAndroid Build Coastguard Worker findRematerializable();
1031*03ce13f7SAndroid Build Coastguard Worker }
1032*03ce13f7SAndroid Build Coastguard Worker
1033*03ce13f7SAndroid Build Coastguard Worker namespace {
1034*03ce13f7SAndroid Build Coastguard Worker
1035*03ce13f7SAndroid Build Coastguard Worker // Helpers for findRematerializable(). For each of them, if a suitable
1036*03ce13f7SAndroid Build Coastguard Worker // rematerialization is found, the instruction's Dest variable is set to be
1037*03ce13f7SAndroid Build Coastguard Worker // rematerializable and it returns true, otherwise it returns false.
1038*03ce13f7SAndroid Build Coastguard Worker
rematerializeArithmetic(const Inst * Instr)1039*03ce13f7SAndroid Build Coastguard Worker bool rematerializeArithmetic(const Inst *Instr) {
1040*03ce13f7SAndroid Build Coastguard Worker // Check that it's an Arithmetic instruction with an Add operation.
1041*03ce13f7SAndroid Build Coastguard Worker auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr);
1042*03ce13f7SAndroid Build Coastguard Worker if (Arith == nullptr || Arith->getOp() != InstArithmetic::Add)
1043*03ce13f7SAndroid Build Coastguard Worker return false;
1044*03ce13f7SAndroid Build Coastguard Worker // Check that Src(0) is rematerializable.
1045*03ce13f7SAndroid Build Coastguard Worker auto *Src0Var = llvm::dyn_cast<Variable>(Arith->getSrc(0));
1046*03ce13f7SAndroid Build Coastguard Worker if (Src0Var == nullptr || !Src0Var->isRematerializable())
1047*03ce13f7SAndroid Build Coastguard Worker return false;
1048*03ce13f7SAndroid Build Coastguard Worker // Check that Src(1) is an immediate.
1049*03ce13f7SAndroid Build Coastguard Worker auto *Src1Imm = llvm::dyn_cast<ConstantInteger32>(Arith->getSrc(1));
1050*03ce13f7SAndroid Build Coastguard Worker if (Src1Imm == nullptr)
1051*03ce13f7SAndroid Build Coastguard Worker return false;
1052*03ce13f7SAndroid Build Coastguard Worker Arith->getDest()->setRematerializable(
1053*03ce13f7SAndroid Build Coastguard Worker Src0Var->getRegNum(), Src0Var->getStackOffset() + Src1Imm->getValue());
1054*03ce13f7SAndroid Build Coastguard Worker return true;
1055*03ce13f7SAndroid Build Coastguard Worker }
1056*03ce13f7SAndroid Build Coastguard Worker
rematerializeAssign(const Inst * Instr)1057*03ce13f7SAndroid Build Coastguard Worker bool rematerializeAssign(const Inst *Instr) {
1058*03ce13f7SAndroid Build Coastguard Worker // An InstAssign only originates from an inttoptr or ptrtoint instruction,
1059*03ce13f7SAndroid Build Coastguard Worker // which never occurs in a MINIMAL build.
1060*03ce13f7SAndroid Build Coastguard Worker if (BuildDefs::minimal())
1061*03ce13f7SAndroid Build Coastguard Worker return false;
1062*03ce13f7SAndroid Build Coastguard Worker // Check that it's an Assign instruction.
1063*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<InstAssign>(Instr))
1064*03ce13f7SAndroid Build Coastguard Worker return false;
1065*03ce13f7SAndroid Build Coastguard Worker // Check that Src(0) is rematerializable.
1066*03ce13f7SAndroid Build Coastguard Worker auto *Src0Var = llvm::dyn_cast<Variable>(Instr->getSrc(0));
1067*03ce13f7SAndroid Build Coastguard Worker if (Src0Var == nullptr || !Src0Var->isRematerializable())
1068*03ce13f7SAndroid Build Coastguard Worker return false;
1069*03ce13f7SAndroid Build Coastguard Worker Instr->getDest()->setRematerializable(Src0Var->getRegNum(),
1070*03ce13f7SAndroid Build Coastguard Worker Src0Var->getStackOffset());
1071*03ce13f7SAndroid Build Coastguard Worker return true;
1072*03ce13f7SAndroid Build Coastguard Worker }
1073*03ce13f7SAndroid Build Coastguard Worker
rematerializeCast(const Inst * Instr)1074*03ce13f7SAndroid Build Coastguard Worker bool rematerializeCast(const Inst *Instr) {
1075*03ce13f7SAndroid Build Coastguard Worker // An pointer-type bitcast never occurs in a MINIMAL build.
1076*03ce13f7SAndroid Build Coastguard Worker if (BuildDefs::minimal())
1077*03ce13f7SAndroid Build Coastguard Worker return false;
1078*03ce13f7SAndroid Build Coastguard Worker // Check that it's a Cast instruction with a Bitcast operation.
1079*03ce13f7SAndroid Build Coastguard Worker auto *Cast = llvm::dyn_cast<InstCast>(Instr);
1080*03ce13f7SAndroid Build Coastguard Worker if (Cast == nullptr || Cast->getCastKind() != InstCast::Bitcast)
1081*03ce13f7SAndroid Build Coastguard Worker return false;
1082*03ce13f7SAndroid Build Coastguard Worker // Check that Src(0) is rematerializable.
1083*03ce13f7SAndroid Build Coastguard Worker auto *Src0Var = llvm::dyn_cast<Variable>(Cast->getSrc(0));
1084*03ce13f7SAndroid Build Coastguard Worker if (Src0Var == nullptr || !Src0Var->isRematerializable())
1085*03ce13f7SAndroid Build Coastguard Worker return false;
1086*03ce13f7SAndroid Build Coastguard Worker // Check that Dest and Src(0) have the same type.
1087*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Cast->getDest();
1088*03ce13f7SAndroid Build Coastguard Worker if (Dest->getType() != Src0Var->getType())
1089*03ce13f7SAndroid Build Coastguard Worker return false;
1090*03ce13f7SAndroid Build Coastguard Worker Dest->setRematerializable(Src0Var->getRegNum(), Src0Var->getStackOffset());
1091*03ce13f7SAndroid Build Coastguard Worker return true;
1092*03ce13f7SAndroid Build Coastguard Worker }
1093*03ce13f7SAndroid Build Coastguard Worker
1094*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
1095*03ce13f7SAndroid Build Coastguard Worker
1096*03ce13f7SAndroid Build Coastguard Worker /// Scan the function to find additional rematerializable variables. This is
1097*03ce13f7SAndroid Build Coastguard Worker /// possible when the source operand of an InstAssignment is a rematerializable
1098*03ce13f7SAndroid Build Coastguard Worker /// variable, or the same for a pointer-type InstCast::Bitcast, or when an
1099*03ce13f7SAndroid Build Coastguard Worker /// InstArithmetic is an add of a rematerializable variable and an immediate.
1100*03ce13f7SAndroid Build Coastguard Worker /// Note that InstAssignment instructions and pointer-type InstCast::Bitcast
1101*03ce13f7SAndroid Build Coastguard Worker /// instructions generally only come about from the IceConverter's treatment of
1102*03ce13f7SAndroid Build Coastguard Worker /// inttoptr, ptrtoint, and bitcast instructions. TODO(stichnot): Consider
1103*03ce13f7SAndroid Build Coastguard Worker /// other possibilities, however unlikely, such as InstArithmetic::Sub, or
1104*03ce13f7SAndroid Build Coastguard Worker /// commutativity.
findRematerializable()1105*03ce13f7SAndroid Build Coastguard Worker void Cfg::findRematerializable() {
1106*03ce13f7SAndroid Build Coastguard Worker // Scan the instructions in order, and repeat until no new opportunities are
1107*03ce13f7SAndroid Build Coastguard Worker // found. It may take more than one iteration because a variable's defining
1108*03ce13f7SAndroid Build Coastguard Worker // block may happen to come after a block where it is used, depending on the
1109*03ce13f7SAndroid Build Coastguard Worker // CfgNode linearization order.
1110*03ce13f7SAndroid Build Coastguard Worker bool FoundNewAssignment;
1111*03ce13f7SAndroid Build Coastguard Worker do {
1112*03ce13f7SAndroid Build Coastguard Worker FoundNewAssignment = false;
1113*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : getNodes()) {
1114*03ce13f7SAndroid Build Coastguard Worker // No need to process Phi instructions.
1115*03ce13f7SAndroid Build Coastguard Worker for (Inst &Instr : Node->getInsts()) {
1116*03ce13f7SAndroid Build Coastguard Worker if (Instr.isDeleted())
1117*03ce13f7SAndroid Build Coastguard Worker continue;
1118*03ce13f7SAndroid Build Coastguard Worker Variable *Dest = Instr.getDest();
1119*03ce13f7SAndroid Build Coastguard Worker if (Dest == nullptr || Dest->isRematerializable())
1120*03ce13f7SAndroid Build Coastguard Worker continue;
1121*03ce13f7SAndroid Build Coastguard Worker if (rematerializeArithmetic(&Instr) || rematerializeAssign(&Instr) ||
1122*03ce13f7SAndroid Build Coastguard Worker rematerializeCast(&Instr)) {
1123*03ce13f7SAndroid Build Coastguard Worker FoundNewAssignment = true;
1124*03ce13f7SAndroid Build Coastguard Worker }
1125*03ce13f7SAndroid Build Coastguard Worker }
1126*03ce13f7SAndroid Build Coastguard Worker }
1127*03ce13f7SAndroid Build Coastguard Worker } while (FoundNewAssignment);
1128*03ce13f7SAndroid Build Coastguard Worker }
1129*03ce13f7SAndroid Build Coastguard Worker
doAddressOpt()1130*03ce13f7SAndroid Build Coastguard Worker void Cfg::doAddressOpt() {
1131*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_doAddressOpt, this);
1132*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
1133*03ce13f7SAndroid Build Coastguard Worker Node->doAddressOpt();
1134*03ce13f7SAndroid Build Coastguard Worker }
1135*03ce13f7SAndroid Build Coastguard Worker
1136*03ce13f7SAndroid Build Coastguard Worker namespace {
1137*03ce13f7SAndroid Build Coastguard Worker // ShuffleVectorUtils implements helper functions for rematerializing
1138*03ce13f7SAndroid Build Coastguard Worker // shufflevector instructions from a sequence of extractelement/insertelement
1139*03ce13f7SAndroid Build Coastguard Worker // instructions. It looks for the following pattern:
1140*03ce13f7SAndroid Build Coastguard Worker //
1141*03ce13f7SAndroid Build Coastguard Worker // %t0 = extractelement A, %n0
1142*03ce13f7SAndroid Build Coastguard Worker // %t1 = extractelement B, %n1
1143*03ce13f7SAndroid Build Coastguard Worker // %t2 = extractelement C, %n2
1144*03ce13f7SAndroid Build Coastguard Worker // ...
1145*03ce13f7SAndroid Build Coastguard Worker // %tN = extractelement N, %nN
1146*03ce13f7SAndroid Build Coastguard Worker // %d0 = insertelement undef, %t0, 0
1147*03ce13f7SAndroid Build Coastguard Worker // %d1 = insertelement %d0, %t1, 1
1148*03ce13f7SAndroid Build Coastguard Worker // %d2 = insertelement %d1, %t2, 2
1149*03ce13f7SAndroid Build Coastguard Worker // ...
1150*03ce13f7SAndroid Build Coastguard Worker // %dest = insertelement %d_N-1, %tN, N
1151*03ce13f7SAndroid Build Coastguard Worker //
1152*03ce13f7SAndroid Build Coastguard Worker // where N is num_element(typeof(%dest)), and A, B, C, ... N are at most two
1153*03ce13f7SAndroid Build Coastguard Worker // distinct variables.
1154*03ce13f7SAndroid Build Coastguard Worker namespace ShuffleVectorUtils {
1155*03ce13f7SAndroid Build Coastguard Worker // findAllInserts is used when searching for all the insertelements that are
1156*03ce13f7SAndroid Build Coastguard Worker // used in a shufflevector operation. This function works recursively, when
1157*03ce13f7SAndroid Build Coastguard Worker // invoked with I = i, the function assumes Insts[i] is the last found
1158*03ce13f7SAndroid Build Coastguard Worker // insertelement in the chain. The next insertelement insertruction is saved in
1159*03ce13f7SAndroid Build Coastguard Worker // Insts[i+1].
findAllInserts(Cfg * Func,GlobalContext * Ctx,VariablesMetadata * VM,CfgVector<const Inst * > * Insts,SizeT I=0)1160*03ce13f7SAndroid Build Coastguard Worker bool findAllInserts(Cfg *Func, GlobalContext *Ctx, VariablesMetadata *VM,
1161*03ce13f7SAndroid Build Coastguard Worker CfgVector<const Inst *> *Insts, SizeT I = 0) {
1162*03ce13f7SAndroid Build Coastguard Worker const bool Verbose = BuildDefs::dump() && Func->isVerbose(IceV_ShufMat);
1163*03ce13f7SAndroid Build Coastguard Worker
1164*03ce13f7SAndroid Build Coastguard Worker if (I > Insts->size()) {
1165*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1166*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\tToo many inserts.\n";
1167*03ce13f7SAndroid Build Coastguard Worker }
1168*03ce13f7SAndroid Build Coastguard Worker return false;
1169*03ce13f7SAndroid Build Coastguard Worker }
1170*03ce13f7SAndroid Build Coastguard Worker
1171*03ce13f7SAndroid Build Coastguard Worker const auto *LastInsert = Insts->at(I);
1172*03ce13f7SAndroid Build Coastguard Worker assert(llvm::isa<InstInsertElement>(LastInsert));
1173*03ce13f7SAndroid Build Coastguard Worker
1174*03ce13f7SAndroid Build Coastguard Worker if (I == Insts->size() - 1) {
1175*03ce13f7SAndroid Build Coastguard Worker // Matching against undef is not really needed because the value in Src(0)
1176*03ce13f7SAndroid Build Coastguard Worker // will be totally overwritten. We still enforce it anyways because the
1177*03ce13f7SAndroid Build Coastguard Worker // PNaCl toolchain generates the bitcode with it.
1178*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<ConstantUndef>(LastInsert->getSrc(0))) {
1179*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1180*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\tSrc0 is not undef: " << I << " "
1181*03ce13f7SAndroid Build Coastguard Worker << Insts->size();
1182*03ce13f7SAndroid Build Coastguard Worker LastInsert->dump(Func);
1183*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\n";
1184*03ce13f7SAndroid Build Coastguard Worker }
1185*03ce13f7SAndroid Build Coastguard Worker return false;
1186*03ce13f7SAndroid Build Coastguard Worker }
1187*03ce13f7SAndroid Build Coastguard Worker
1188*03ce13f7SAndroid Build Coastguard Worker // The following loop ensures that the insertelements are sorted. In theory,
1189*03ce13f7SAndroid Build Coastguard Worker // we could relax this restriction and allow any order. As long as each
1190*03ce13f7SAndroid Build Coastguard Worker // index appears exactly once, this chain is still a candidate for becoming
1191*03ce13f7SAndroid Build Coastguard Worker // a shufflevector. The Insts vector is traversed backwards because the
1192*03ce13f7SAndroid Build Coastguard Worker // instructions are "enqueued" in reverse order.
1193*03ce13f7SAndroid Build Coastguard Worker int32_t ExpectedElement = 0;
1194*03ce13f7SAndroid Build Coastguard Worker for (const auto *I : reverse_range(*Insts)) {
1195*03ce13f7SAndroid Build Coastguard Worker if (llvm::cast<ConstantInteger32>(I->getSrc(2))->getValue() !=
1196*03ce13f7SAndroid Build Coastguard Worker ExpectedElement) {
1197*03ce13f7SAndroid Build Coastguard Worker return false;
1198*03ce13f7SAndroid Build Coastguard Worker }
1199*03ce13f7SAndroid Build Coastguard Worker ++ExpectedElement;
1200*03ce13f7SAndroid Build Coastguard Worker }
1201*03ce13f7SAndroid Build Coastguard Worker return true;
1202*03ce13f7SAndroid Build Coastguard Worker }
1203*03ce13f7SAndroid Build Coastguard Worker
1204*03ce13f7SAndroid Build Coastguard Worker const auto *Src0V = llvm::cast<Variable>(LastInsert->getSrc(0));
1205*03ce13f7SAndroid Build Coastguard Worker const auto *Def = VM->getSingleDefinition(Src0V);
1206*03ce13f7SAndroid Build Coastguard Worker
1207*03ce13f7SAndroid Build Coastguard Worker // Only optimize if the first operand in
1208*03ce13f7SAndroid Build Coastguard Worker //
1209*03ce13f7SAndroid Build Coastguard Worker // Dest = insertelement A, B, 10
1210*03ce13f7SAndroid Build Coastguard Worker //
1211*03ce13f7SAndroid Build Coastguard Worker // is singly-def'ed.
1212*03ce13f7SAndroid Build Coastguard Worker if (Def == nullptr) {
1213*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1214*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\tmulti-def: ";
1215*03ce13f7SAndroid Build Coastguard Worker (*Insts)[I]->dump(Func);
1216*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\n";
1217*03ce13f7SAndroid Build Coastguard Worker }
1218*03ce13f7SAndroid Build Coastguard Worker return false;
1219*03ce13f7SAndroid Build Coastguard Worker }
1220*03ce13f7SAndroid Build Coastguard Worker
1221*03ce13f7SAndroid Build Coastguard Worker // We also require the (single) definition to come from an insertelement
1222*03ce13f7SAndroid Build Coastguard Worker // instruction.
1223*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<InstInsertElement>(Def)) {
1224*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1225*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\tnot insert element: ";
1226*03ce13f7SAndroid Build Coastguard Worker Def->dump(Func);
1227*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\n";
1228*03ce13f7SAndroid Build Coastguard Worker }
1229*03ce13f7SAndroid Build Coastguard Worker return false;
1230*03ce13f7SAndroid Build Coastguard Worker }
1231*03ce13f7SAndroid Build Coastguard Worker
1232*03ce13f7SAndroid Build Coastguard Worker // Everything seems fine, so we save Def in Insts, and delegate the decision
1233*03ce13f7SAndroid Build Coastguard Worker // to findAllInserts.
1234*03ce13f7SAndroid Build Coastguard Worker (*Insts)[I + 1] = Def;
1235*03ce13f7SAndroid Build Coastguard Worker
1236*03ce13f7SAndroid Build Coastguard Worker return findAllInserts(Func, Ctx, VM, Insts, I + 1);
1237*03ce13f7SAndroid Build Coastguard Worker }
1238*03ce13f7SAndroid Build Coastguard Worker
1239*03ce13f7SAndroid Build Coastguard Worker // insertsLastElement returns true if Insert is inserting an element in the last
1240*03ce13f7SAndroid Build Coastguard Worker // position of a vector.
insertsLastElement(const Inst & Insert)1241*03ce13f7SAndroid Build Coastguard Worker bool insertsLastElement(const Inst &Insert) {
1242*03ce13f7SAndroid Build Coastguard Worker const Type DestTy = Insert.getDest()->getType();
1243*03ce13f7SAndroid Build Coastguard Worker assert(isVectorType(DestTy));
1244*03ce13f7SAndroid Build Coastguard Worker const SizeT Elem =
1245*03ce13f7SAndroid Build Coastguard Worker llvm::cast<ConstantInteger32>(Insert.getSrc(2))->getValue();
1246*03ce13f7SAndroid Build Coastguard Worker return Elem == typeNumElements(DestTy) - 1;
1247*03ce13f7SAndroid Build Coastguard Worker }
1248*03ce13f7SAndroid Build Coastguard Worker
1249*03ce13f7SAndroid Build Coastguard Worker // findAllExtracts goes over all the insertelement instructions that are
1250*03ce13f7SAndroid Build Coastguard Worker // candidates to be replaced by a shufflevector, and searches for all the
1251*03ce13f7SAndroid Build Coastguard Worker // definitions of the elements being inserted. If all of the elements are the
1252*03ce13f7SAndroid Build Coastguard Worker // result of an extractelement instruction, and all of the extractelements
1253*03ce13f7SAndroid Build Coastguard Worker // operate on at most two different sources, than the instructions can be
1254*03ce13f7SAndroid Build Coastguard Worker // replaced by a shufflevector.
findAllExtracts(Cfg * Func,GlobalContext * Ctx,VariablesMetadata * VM,const CfgVector<const Inst * > & Insts,Variable ** Src0,Variable ** Src1,CfgVector<const Inst * > * Extracts)1255*03ce13f7SAndroid Build Coastguard Worker bool findAllExtracts(Cfg *Func, GlobalContext *Ctx, VariablesMetadata *VM,
1256*03ce13f7SAndroid Build Coastguard Worker const CfgVector<const Inst *> &Insts, Variable **Src0,
1257*03ce13f7SAndroid Build Coastguard Worker Variable **Src1, CfgVector<const Inst *> *Extracts) {
1258*03ce13f7SAndroid Build Coastguard Worker const bool Verbose = BuildDefs::dump() && Func->isVerbose(IceV_ShufMat);
1259*03ce13f7SAndroid Build Coastguard Worker
1260*03ce13f7SAndroid Build Coastguard Worker *Src0 = nullptr;
1261*03ce13f7SAndroid Build Coastguard Worker *Src1 = nullptr;
1262*03ce13f7SAndroid Build Coastguard Worker assert(Insts.size() > 0);
1263*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0; I < Insts.size(); ++I) {
1264*03ce13f7SAndroid Build Coastguard Worker const auto *Insert = Insts.at(I);
1265*03ce13f7SAndroid Build Coastguard Worker const auto *Src1V = llvm::dyn_cast<Variable>(Insert->getSrc(1));
1266*03ce13f7SAndroid Build Coastguard Worker if (Src1V == nullptr) {
1267*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1268*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "src(1) is not a variable: ";
1269*03ce13f7SAndroid Build Coastguard Worker Insert->dump(Func);
1270*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\n";
1271*03ce13f7SAndroid Build Coastguard Worker }
1272*03ce13f7SAndroid Build Coastguard Worker return false;
1273*03ce13f7SAndroid Build Coastguard Worker }
1274*03ce13f7SAndroid Build Coastguard Worker
1275*03ce13f7SAndroid Build Coastguard Worker const auto *Def = VM->getSingleDefinition(Src1V);
1276*03ce13f7SAndroid Build Coastguard Worker if (Def == nullptr) {
1277*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1278*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "multi-def src(1): ";
1279*03ce13f7SAndroid Build Coastguard Worker Insert->dump(Func);
1280*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\n";
1281*03ce13f7SAndroid Build Coastguard Worker }
1282*03ce13f7SAndroid Build Coastguard Worker return false;
1283*03ce13f7SAndroid Build Coastguard Worker }
1284*03ce13f7SAndroid Build Coastguard Worker
1285*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<InstExtractElement>(Def)) {
1286*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1287*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "not extractelement: ";
1288*03ce13f7SAndroid Build Coastguard Worker Def->dump(Func);
1289*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "\n";
1290*03ce13f7SAndroid Build Coastguard Worker }
1291*03ce13f7SAndroid Build Coastguard Worker return false;
1292*03ce13f7SAndroid Build Coastguard Worker }
1293*03ce13f7SAndroid Build Coastguard Worker
1294*03ce13f7SAndroid Build Coastguard Worker auto *Src = llvm::cast<Variable>(Def->getSrc(0));
1295*03ce13f7SAndroid Build Coastguard Worker if (*Src0 == nullptr) {
1296*03ce13f7SAndroid Build Coastguard Worker // No sources yet. Save Src to Src0.
1297*03ce13f7SAndroid Build Coastguard Worker *Src0 = Src;
1298*03ce13f7SAndroid Build Coastguard Worker } else if (*Src1 == nullptr) {
1299*03ce13f7SAndroid Build Coastguard Worker // We already have a source, so we might save Src in Src1 -- but only if
1300*03ce13f7SAndroid Build Coastguard Worker // Src0 is not Src.
1301*03ce13f7SAndroid Build Coastguard Worker if (*Src0 != Src) {
1302*03ce13f7SAndroid Build Coastguard Worker *Src1 = Src;
1303*03ce13f7SAndroid Build Coastguard Worker }
1304*03ce13f7SAndroid Build Coastguard Worker } else if (Src != *Src0 && Src != *Src1) {
1305*03ce13f7SAndroid Build Coastguard Worker // More than two sources, so we can't rematerialize the shufflevector
1306*03ce13f7SAndroid Build Coastguard Worker // instruction.
1307*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1308*03ce13f7SAndroid Build Coastguard Worker Ctx->getStrDump() << "Can't shuffle more than two sources.\n";
1309*03ce13f7SAndroid Build Coastguard Worker }
1310*03ce13f7SAndroid Build Coastguard Worker return false;
1311*03ce13f7SAndroid Build Coastguard Worker }
1312*03ce13f7SAndroid Build Coastguard Worker
1313*03ce13f7SAndroid Build Coastguard Worker (*Extracts)[I] = Def;
1314*03ce13f7SAndroid Build Coastguard Worker }
1315*03ce13f7SAndroid Build Coastguard Worker
1316*03ce13f7SAndroid Build Coastguard Worker // We should have seen at least one source operand.
1317*03ce13f7SAndroid Build Coastguard Worker assert(*Src0 != nullptr);
1318*03ce13f7SAndroid Build Coastguard Worker
1319*03ce13f7SAndroid Build Coastguard Worker // If a second source was not seen, then we just make Src1 = Src0 to simplify
1320*03ce13f7SAndroid Build Coastguard Worker // things down stream. This should not matter, as all of the indexes in the
1321*03ce13f7SAndroid Build Coastguard Worker // shufflevector instruction will point to Src0.
1322*03ce13f7SAndroid Build Coastguard Worker if (*Src1 == nullptr) {
1323*03ce13f7SAndroid Build Coastguard Worker *Src1 = *Src0;
1324*03ce13f7SAndroid Build Coastguard Worker }
1325*03ce13f7SAndroid Build Coastguard Worker
1326*03ce13f7SAndroid Build Coastguard Worker return true;
1327*03ce13f7SAndroid Build Coastguard Worker }
1328*03ce13f7SAndroid Build Coastguard Worker
1329*03ce13f7SAndroid Build Coastguard Worker } // end of namespace ShuffleVectorUtils
1330*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
1331*03ce13f7SAndroid Build Coastguard Worker
materializeVectorShuffles()1332*03ce13f7SAndroid Build Coastguard Worker void Cfg::materializeVectorShuffles() {
1333*03ce13f7SAndroid Build Coastguard Worker const bool Verbose = BuildDefs::dump() && isVerbose(IceV_ShufMat);
1334*03ce13f7SAndroid Build Coastguard Worker
1335*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<OstreamLocker> L;
1336*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1337*03ce13f7SAndroid Build Coastguard Worker L.reset(new OstreamLocker(getContext()));
1338*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\nShuffle materialization:\n";
1339*03ce13f7SAndroid Build Coastguard Worker }
1340*03ce13f7SAndroid Build Coastguard Worker
1341*03ce13f7SAndroid Build Coastguard Worker // MaxVectorElements is the maximum number of elements in the vector types
1342*03ce13f7SAndroid Build Coastguard Worker // handled by Subzero. We use it to create the Inserts and Extracts vectors
1343*03ce13f7SAndroid Build Coastguard Worker // with the appropriate size, thus avoiding resize() calls.
1344*03ce13f7SAndroid Build Coastguard Worker const SizeT MaxVectorElements = typeNumElements(IceType_v16i8);
1345*03ce13f7SAndroid Build Coastguard Worker CfgVector<const Inst *> Inserts(MaxVectorElements);
1346*03ce13f7SAndroid Build Coastguard Worker CfgVector<const Inst *> Extracts(MaxVectorElements);
1347*03ce13f7SAndroid Build Coastguard Worker
1348*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_materializeVectorShuffles, this);
1349*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
1350*03ce13f7SAndroid Build Coastguard Worker for (auto &Instr : Node->getInsts()) {
1351*03ce13f7SAndroid Build Coastguard Worker if (!llvm::isa<InstInsertElement>(Instr)) {
1352*03ce13f7SAndroid Build Coastguard Worker continue;
1353*03ce13f7SAndroid Build Coastguard Worker }
1354*03ce13f7SAndroid Build Coastguard Worker if (!ShuffleVectorUtils::insertsLastElement(Instr)) {
1355*03ce13f7SAndroid Build Coastguard Worker // To avoid wasting time, we only start the pattern match at the last
1356*03ce13f7SAndroid Build Coastguard Worker // insertelement instruction -- and go backwards from there.
1357*03ce13f7SAndroid Build Coastguard Worker continue;
1358*03ce13f7SAndroid Build Coastguard Worker }
1359*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1360*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\tCandidate: ";
1361*03ce13f7SAndroid Build Coastguard Worker Instr.dump(this);
1362*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\n";
1363*03ce13f7SAndroid Build Coastguard Worker }
1364*03ce13f7SAndroid Build Coastguard Worker Inserts.resize(typeNumElements(Instr.getDest()->getType()));
1365*03ce13f7SAndroid Build Coastguard Worker Inserts[0] = &Instr;
1366*03ce13f7SAndroid Build Coastguard Worker if (!ShuffleVectorUtils::findAllInserts(this, getContext(),
1367*03ce13f7SAndroid Build Coastguard Worker VMetadata.get(), &Inserts)) {
1368*03ce13f7SAndroid Build Coastguard Worker // If we fail to find a sequence of insertelements, we stop the
1369*03ce13f7SAndroid Build Coastguard Worker // optimization.
1370*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1371*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\tFalse alarm.\n";
1372*03ce13f7SAndroid Build Coastguard Worker }
1373*03ce13f7SAndroid Build Coastguard Worker continue;
1374*03ce13f7SAndroid Build Coastguard Worker }
1375*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1376*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\tFound the following insertelement: \n";
1377*03ce13f7SAndroid Build Coastguard Worker for (auto *I : reverse_range(Inserts)) {
1378*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\t\t";
1379*03ce13f7SAndroid Build Coastguard Worker I->dump(this);
1380*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\n";
1381*03ce13f7SAndroid Build Coastguard Worker }
1382*03ce13f7SAndroid Build Coastguard Worker }
1383*03ce13f7SAndroid Build Coastguard Worker Extracts.resize(Inserts.size());
1384*03ce13f7SAndroid Build Coastguard Worker Variable *Src0;
1385*03ce13f7SAndroid Build Coastguard Worker Variable *Src1;
1386*03ce13f7SAndroid Build Coastguard Worker if (!ShuffleVectorUtils::findAllExtracts(this, getContext(),
1387*03ce13f7SAndroid Build Coastguard Worker VMetadata.get(), Inserts, &Src0,
1388*03ce13f7SAndroid Build Coastguard Worker &Src1, &Extracts)) {
1389*03ce13f7SAndroid Build Coastguard Worker // If we fail to match the definitions of the insertelements' sources
1390*03ce13f7SAndroid Build Coastguard Worker // with extractelement instructions -- or if those instructions operate
1391*03ce13f7SAndroid Build Coastguard Worker // on more than two different variables -- we stop the optimization.
1392*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1393*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\tFailed to match extractelements.\n";
1394*03ce13f7SAndroid Build Coastguard Worker }
1395*03ce13f7SAndroid Build Coastguard Worker continue;
1396*03ce13f7SAndroid Build Coastguard Worker }
1397*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1398*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump()
1399*03ce13f7SAndroid Build Coastguard Worker << "\tFound the following insert/extract element pairs: \n";
1400*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0; I < Inserts.size(); ++I) {
1401*03ce13f7SAndroid Build Coastguard Worker const SizeT Pos = Inserts.size() - I - 1;
1402*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\t\tInsert : ";
1403*03ce13f7SAndroid Build Coastguard Worker Inserts[Pos]->dump(this);
1404*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\n\t\tExtract: ";
1405*03ce13f7SAndroid Build Coastguard Worker Extracts[Pos]->dump(this);
1406*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\n";
1407*03ce13f7SAndroid Build Coastguard Worker }
1408*03ce13f7SAndroid Build Coastguard Worker }
1409*03ce13f7SAndroid Build Coastguard Worker
1410*03ce13f7SAndroid Build Coastguard Worker assert(Src0 != nullptr);
1411*03ce13f7SAndroid Build Coastguard Worker assert(Src1 != nullptr);
1412*03ce13f7SAndroid Build Coastguard Worker
1413*03ce13f7SAndroid Build Coastguard Worker auto *ShuffleVector =
1414*03ce13f7SAndroid Build Coastguard Worker InstShuffleVector::create(this, Instr.getDest(), Src0, Src1);
1415*03ce13f7SAndroid Build Coastguard Worker assert(ShuffleVector->getSrc(0) == Src0);
1416*03ce13f7SAndroid Build Coastguard Worker assert(ShuffleVector->getSrc(1) == Src1);
1417*03ce13f7SAndroid Build Coastguard Worker for (SizeT I = 0; I < Extracts.size(); ++I) {
1418*03ce13f7SAndroid Build Coastguard Worker const SizeT Pos = Extracts.size() - I - 1;
1419*03ce13f7SAndroid Build Coastguard Worker auto *Index = llvm::cast<ConstantInteger32>(Extracts[Pos]->getSrc(1));
1420*03ce13f7SAndroid Build Coastguard Worker if (Src0 == Extracts[Pos]->getSrc(0)) {
1421*03ce13f7SAndroid Build Coastguard Worker ShuffleVector->addIndex(Index);
1422*03ce13f7SAndroid Build Coastguard Worker } else {
1423*03ce13f7SAndroid Build Coastguard Worker ShuffleVector->addIndex(llvm::cast<ConstantInteger32>(
1424*03ce13f7SAndroid Build Coastguard Worker Ctx->getConstantInt32(Index->getValue() + Extracts.size())));
1425*03ce13f7SAndroid Build Coastguard Worker }
1426*03ce13f7SAndroid Build Coastguard Worker }
1427*03ce13f7SAndroid Build Coastguard Worker
1428*03ce13f7SAndroid Build Coastguard Worker if (Verbose) {
1429*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "Created: ";
1430*03ce13f7SAndroid Build Coastguard Worker ShuffleVector->dump(this);
1431*03ce13f7SAndroid Build Coastguard Worker getContext()->getStrDump() << "\n";
1432*03ce13f7SAndroid Build Coastguard Worker }
1433*03ce13f7SAndroid Build Coastguard Worker
1434*03ce13f7SAndroid Build Coastguard Worker Instr.setDeleted();
1435*03ce13f7SAndroid Build Coastguard Worker auto &LoweringContext = getTarget()->getContext();
1436*03ce13f7SAndroid Build Coastguard Worker LoweringContext.setInsertPoint(instToIterator(&Instr));
1437*03ce13f7SAndroid Build Coastguard Worker LoweringContext.insert(ShuffleVector);
1438*03ce13f7SAndroid Build Coastguard Worker }
1439*03ce13f7SAndroid Build Coastguard Worker }
1440*03ce13f7SAndroid Build Coastguard Worker }
1441*03ce13f7SAndroid Build Coastguard Worker
genCode()1442*03ce13f7SAndroid Build Coastguard Worker void Cfg::genCode() {
1443*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_genCode, this);
1444*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
1445*03ce13f7SAndroid Build Coastguard Worker Node->genCode();
1446*03ce13f7SAndroid Build Coastguard Worker }
1447*03ce13f7SAndroid Build Coastguard Worker
1448*03ce13f7SAndroid Build Coastguard Worker // Compute the stack frame layout.
genFrame()1449*03ce13f7SAndroid Build Coastguard Worker void Cfg::genFrame() {
1450*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_genFrame, this);
1451*03ce13f7SAndroid Build Coastguard Worker getTarget()->addProlog(Entry);
1452*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
1453*03ce13f7SAndroid Build Coastguard Worker if (Node->getHasReturn())
1454*03ce13f7SAndroid Build Coastguard Worker getTarget()->addEpilog(Node);
1455*03ce13f7SAndroid Build Coastguard Worker }
1456*03ce13f7SAndroid Build Coastguard Worker
generateLoopInfo()1457*03ce13f7SAndroid Build Coastguard Worker void Cfg::generateLoopInfo() {
1458*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_computeLoopNestDepth, this);
1459*03ce13f7SAndroid Build Coastguard Worker LoopInfo = ComputeLoopInfo(this);
1460*03ce13f7SAndroid Build Coastguard Worker }
1461*03ce13f7SAndroid Build Coastguard Worker
1462*03ce13f7SAndroid Build Coastguard Worker // This is a lightweight version of live-range-end calculation. Marks the last
1463*03ce13f7SAndroid Build Coastguard Worker // use of only those variables whose definition and uses are completely with a
1464*03ce13f7SAndroid Build Coastguard Worker // single block. It is a quick single pass and doesn't need to iterate until
1465*03ce13f7SAndroid Build Coastguard Worker // convergence.
livenessLightweight()1466*03ce13f7SAndroid Build Coastguard Worker void Cfg::livenessLightweight() {
1467*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_livenessLightweight, this);
1468*03ce13f7SAndroid Build Coastguard Worker getVMetadata()->init(VMK_Uses);
1469*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
1470*03ce13f7SAndroid Build Coastguard Worker Node->livenessLightweight();
1471*03ce13f7SAndroid Build Coastguard Worker }
1472*03ce13f7SAndroid Build Coastguard Worker
liveness(LivenessMode Mode)1473*03ce13f7SAndroid Build Coastguard Worker void Cfg::liveness(LivenessMode Mode) {
1474*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_liveness, this);
1475*03ce13f7SAndroid Build Coastguard Worker // Destroying the previous (if any) Liveness information clears the Liveness
1476*03ce13f7SAndroid Build Coastguard Worker // allocator TLS pointer.
1477*03ce13f7SAndroid Build Coastguard Worker Live = nullptr;
1478*03ce13f7SAndroid Build Coastguard Worker Live = Liveness::create(this, Mode);
1479*03ce13f7SAndroid Build Coastguard Worker
1480*03ce13f7SAndroid Build Coastguard Worker getVMetadata()->init(VMK_Uses);
1481*03ce13f7SAndroid Build Coastguard Worker Live->init();
1482*03ce13f7SAndroid Build Coastguard Worker
1483*03ce13f7SAndroid Build Coastguard Worker // Initialize with all nodes needing to be processed.
1484*03ce13f7SAndroid Build Coastguard Worker BitVector NeedToProcess(Nodes.size(), true);
1485*03ce13f7SAndroid Build Coastguard Worker while (NeedToProcess.any()) {
1486*03ce13f7SAndroid Build Coastguard Worker // Iterate in reverse topological order to speed up convergence.
1487*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : reverse_range(Nodes)) {
1488*03ce13f7SAndroid Build Coastguard Worker if (NeedToProcess[Node->getIndex()]) {
1489*03ce13f7SAndroid Build Coastguard Worker NeedToProcess[Node->getIndex()] = false;
1490*03ce13f7SAndroid Build Coastguard Worker bool Changed = Node->liveness(getLiveness());
1491*03ce13f7SAndroid Build Coastguard Worker if (Changed) {
1492*03ce13f7SAndroid Build Coastguard Worker // If the beginning-of-block liveness changed since the last
1493*03ce13f7SAndroid Build Coastguard Worker // iteration, mark all in-edges as needing to be processed.
1494*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Pred : Node->getInEdges())
1495*03ce13f7SAndroid Build Coastguard Worker NeedToProcess[Pred->getIndex()] = true;
1496*03ce13f7SAndroid Build Coastguard Worker }
1497*03ce13f7SAndroid Build Coastguard Worker }
1498*03ce13f7SAndroid Build Coastguard Worker }
1499*03ce13f7SAndroid Build Coastguard Worker }
1500*03ce13f7SAndroid Build Coastguard Worker if (Mode == Liveness_Intervals) {
1501*03ce13f7SAndroid Build Coastguard Worker // Reset each variable's live range.
1502*03ce13f7SAndroid Build Coastguard Worker for (Variable *Var : Variables)
1503*03ce13f7SAndroid Build Coastguard Worker Var->resetLiveRange();
1504*03ce13f7SAndroid Build Coastguard Worker }
1505*03ce13f7SAndroid Build Coastguard Worker // Make a final pass over each node to delete dead instructions, collect the
1506*03ce13f7SAndroid Build Coastguard Worker // first and last instruction numbers, and add live range segments for that
1507*03ce13f7SAndroid Build Coastguard Worker // node.
1508*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
1509*03ce13f7SAndroid Build Coastguard Worker InstNumberT FirstInstNum = Inst::NumberSentinel;
1510*03ce13f7SAndroid Build Coastguard Worker InstNumberT LastInstNum = Inst::NumberSentinel;
1511*03ce13f7SAndroid Build Coastguard Worker for (Inst &I : Node->getPhis()) {
1512*03ce13f7SAndroid Build Coastguard Worker I.deleteIfDead();
1513*03ce13f7SAndroid Build Coastguard Worker if (Mode == Liveness_Intervals && !I.isDeleted()) {
1514*03ce13f7SAndroid Build Coastguard Worker if (FirstInstNum == Inst::NumberSentinel)
1515*03ce13f7SAndroid Build Coastguard Worker FirstInstNum = I.getNumber();
1516*03ce13f7SAndroid Build Coastguard Worker assert(I.getNumber() > LastInstNum);
1517*03ce13f7SAndroid Build Coastguard Worker LastInstNum = I.getNumber();
1518*03ce13f7SAndroid Build Coastguard Worker }
1519*03ce13f7SAndroid Build Coastguard Worker }
1520*03ce13f7SAndroid Build Coastguard Worker for (Inst &I : Node->getInsts()) {
1521*03ce13f7SAndroid Build Coastguard Worker I.deleteIfDead();
1522*03ce13f7SAndroid Build Coastguard Worker if (Mode == Liveness_Intervals && !I.isDeleted()) {
1523*03ce13f7SAndroid Build Coastguard Worker if (FirstInstNum == Inst::NumberSentinel)
1524*03ce13f7SAndroid Build Coastguard Worker FirstInstNum = I.getNumber();
1525*03ce13f7SAndroid Build Coastguard Worker assert(I.getNumber() > LastInstNum);
1526*03ce13f7SAndroid Build Coastguard Worker LastInstNum = I.getNumber();
1527*03ce13f7SAndroid Build Coastguard Worker }
1528*03ce13f7SAndroid Build Coastguard Worker }
1529*03ce13f7SAndroid Build Coastguard Worker if (Mode == Liveness_Intervals) {
1530*03ce13f7SAndroid Build Coastguard Worker // Special treatment for live in-args. Their liveness needs to extend
1531*03ce13f7SAndroid Build Coastguard Worker // beyond the beginning of the function, otherwise an arg whose only use
1532*03ce13f7SAndroid Build Coastguard Worker // is in the first instruction will end up having the trivial live range
1533*03ce13f7SAndroid Build Coastguard Worker // [2,2) and will *not* interfere with other arguments. So if the first
1534*03ce13f7SAndroid Build Coastguard Worker // instruction of the method is "r=arg1+arg2", both args may be assigned
1535*03ce13f7SAndroid Build Coastguard Worker // the same register. This is accomplished by extending the entry block's
1536*03ce13f7SAndroid Build Coastguard Worker // instruction range from [2,n) to [1,n) which will transform the
1537*03ce13f7SAndroid Build Coastguard Worker // problematic [2,2) live ranges into [1,2). This extension works because
1538*03ce13f7SAndroid Build Coastguard Worker // the entry node is guaranteed to have the lowest instruction numbers.
1539*03ce13f7SAndroid Build Coastguard Worker if (Node == getEntryNode()) {
1540*03ce13f7SAndroid Build Coastguard Worker FirstInstNum = Inst::NumberExtended;
1541*03ce13f7SAndroid Build Coastguard Worker // Just in case the entry node somehow contains no instructions...
1542*03ce13f7SAndroid Build Coastguard Worker if (LastInstNum == Inst::NumberSentinel)
1543*03ce13f7SAndroid Build Coastguard Worker LastInstNum = FirstInstNum;
1544*03ce13f7SAndroid Build Coastguard Worker }
1545*03ce13f7SAndroid Build Coastguard Worker // If this node somehow contains no instructions, don't bother trying to
1546*03ce13f7SAndroid Build Coastguard Worker // add liveness intervals for it, because variables that are live-in and
1547*03ce13f7SAndroid Build Coastguard Worker // live-out will have a bogus interval added.
1548*03ce13f7SAndroid Build Coastguard Worker if (FirstInstNum != Inst::NumberSentinel)
1549*03ce13f7SAndroid Build Coastguard Worker Node->livenessAddIntervals(getLiveness(), FirstInstNum, LastInstNum);
1550*03ce13f7SAndroid Build Coastguard Worker }
1551*03ce13f7SAndroid Build Coastguard Worker }
1552*03ce13f7SAndroid Build Coastguard Worker }
1553*03ce13f7SAndroid Build Coastguard Worker
1554*03ce13f7SAndroid Build Coastguard Worker // Traverse every Variable of every Inst and verify that it appears within the
1555*03ce13f7SAndroid Build Coastguard Worker // Variable's computed live range.
validateLiveness() const1556*03ce13f7SAndroid Build Coastguard Worker bool Cfg::validateLiveness() const {
1557*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_validateLiveness, this);
1558*03ce13f7SAndroid Build Coastguard Worker bool Valid = true;
1559*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Ctx);
1560*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrDump();
1561*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
1562*03ce13f7SAndroid Build Coastguard Worker Inst *FirstInst = nullptr;
1563*03ce13f7SAndroid Build Coastguard Worker for (Inst &Instr : Node->getInsts()) {
1564*03ce13f7SAndroid Build Coastguard Worker if (Instr.isDeleted())
1565*03ce13f7SAndroid Build Coastguard Worker continue;
1566*03ce13f7SAndroid Build Coastguard Worker if (FirstInst == nullptr)
1567*03ce13f7SAndroid Build Coastguard Worker FirstInst = &Instr;
1568*03ce13f7SAndroid Build Coastguard Worker InstNumberT InstNumber = Instr.getNumber();
1569*03ce13f7SAndroid Build Coastguard Worker if (Variable *Dest = Instr.getDest()) {
1570*03ce13f7SAndroid Build Coastguard Worker if (!Dest->getIgnoreLiveness()) {
1571*03ce13f7SAndroid Build Coastguard Worker bool Invalid = false;
1572*03ce13f7SAndroid Build Coastguard Worker constexpr bool IsDest = true;
1573*03ce13f7SAndroid Build Coastguard Worker if (!Dest->getLiveRange().containsValue(InstNumber, IsDest))
1574*03ce13f7SAndroid Build Coastguard Worker Invalid = true;
1575*03ce13f7SAndroid Build Coastguard Worker // Check that this instruction actually *begins* Dest's live range,
1576*03ce13f7SAndroid Build Coastguard Worker // by checking that Dest is not live in the previous instruction. As
1577*03ce13f7SAndroid Build Coastguard Worker // a special exception, we don't check this for the first instruction
1578*03ce13f7SAndroid Build Coastguard Worker // of the block, because a Phi temporary may be live at the end of
1579*03ce13f7SAndroid Build Coastguard Worker // the previous block, and if it is also assigned in the first
1580*03ce13f7SAndroid Build Coastguard Worker // instruction of this block, the adjacent live ranges get merged.
1581*03ce13f7SAndroid Build Coastguard Worker if (&Instr != FirstInst && !Instr.isDestRedefined() &&
1582*03ce13f7SAndroid Build Coastguard Worker Dest->getLiveRange().containsValue(InstNumber - 1, IsDest))
1583*03ce13f7SAndroid Build Coastguard Worker Invalid = true;
1584*03ce13f7SAndroid Build Coastguard Worker if (Invalid) {
1585*03ce13f7SAndroid Build Coastguard Worker Valid = false;
1586*03ce13f7SAndroid Build Coastguard Worker Str << "Liveness error: inst " << Instr.getNumber() << " dest ";
1587*03ce13f7SAndroid Build Coastguard Worker Dest->dump(this);
1588*03ce13f7SAndroid Build Coastguard Worker Str << " live range " << Dest->getLiveRange() << "\n";
1589*03ce13f7SAndroid Build Coastguard Worker }
1590*03ce13f7SAndroid Build Coastguard Worker }
1591*03ce13f7SAndroid Build Coastguard Worker }
1592*03ce13f7SAndroid Build Coastguard Worker FOREACH_VAR_IN_INST(Var, Instr) {
1593*03ce13f7SAndroid Build Coastguard Worker static constexpr bool IsDest = false;
1594*03ce13f7SAndroid Build Coastguard Worker if (!Var->getIgnoreLiveness() &&
1595*03ce13f7SAndroid Build Coastguard Worker !Var->getLiveRange().containsValue(InstNumber, IsDest)) {
1596*03ce13f7SAndroid Build Coastguard Worker Valid = false;
1597*03ce13f7SAndroid Build Coastguard Worker Str << "Liveness error: inst " << Instr.getNumber() << " var ";
1598*03ce13f7SAndroid Build Coastguard Worker Var->dump(this);
1599*03ce13f7SAndroid Build Coastguard Worker Str << " live range " << Var->getLiveRange() << "\n";
1600*03ce13f7SAndroid Build Coastguard Worker }
1601*03ce13f7SAndroid Build Coastguard Worker }
1602*03ce13f7SAndroid Build Coastguard Worker }
1603*03ce13f7SAndroid Build Coastguard Worker }
1604*03ce13f7SAndroid Build Coastguard Worker return Valid;
1605*03ce13f7SAndroid Build Coastguard Worker }
1606*03ce13f7SAndroid Build Coastguard Worker
contractEmptyNodes()1607*03ce13f7SAndroid Build Coastguard Worker void Cfg::contractEmptyNodes() {
1608*03ce13f7SAndroid Build Coastguard Worker // If we're decorating the asm output with register liveness info, this
1609*03ce13f7SAndroid Build Coastguard Worker // information may become corrupted or incorrect after contracting nodes that
1610*03ce13f7SAndroid Build Coastguard Worker // contain only redundant assignments. As such, we disable this pass when
1611*03ce13f7SAndroid Build Coastguard Worker // DecorateAsm is specified. This may make the resulting code look more
1612*03ce13f7SAndroid Build Coastguard Worker // branchy, but it should have no effect on the register assignments.
1613*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getDecorateAsm())
1614*03ce13f7SAndroid Build Coastguard Worker return;
1615*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
1616*03ce13f7SAndroid Build Coastguard Worker Node->contractIfEmpty();
1617*03ce13f7SAndroid Build Coastguard Worker }
1618*03ce13f7SAndroid Build Coastguard Worker }
1619*03ce13f7SAndroid Build Coastguard Worker
doBranchOpt()1620*03ce13f7SAndroid Build Coastguard Worker void Cfg::doBranchOpt() {
1621*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_doBranchOpt, this);
1622*03ce13f7SAndroid Build Coastguard Worker for (auto I = Nodes.begin(), E = Nodes.end(); I != E; ++I) {
1623*03ce13f7SAndroid Build Coastguard Worker auto NextNode = I + 1;
1624*03ce13f7SAndroid Build Coastguard Worker (*I)->doBranchOpt(NextNode == E ? nullptr : *NextNode);
1625*03ce13f7SAndroid Build Coastguard Worker }
1626*03ce13f7SAndroid Build Coastguard Worker }
1627*03ce13f7SAndroid Build Coastguard Worker
1628*03ce13f7SAndroid Build Coastguard Worker // ======================== Dump routines ======================== //
1629*03ce13f7SAndroid Build Coastguard Worker
1630*03ce13f7SAndroid Build Coastguard Worker // emitTextHeader() is not target-specific (apart from what is abstracted by
1631*03ce13f7SAndroid Build Coastguard Worker // the Assembler), so it is defined here rather than in the target lowering
1632*03ce13f7SAndroid Build Coastguard Worker // class.
emitTextHeader(GlobalString Name,GlobalContext * Ctx,const Assembler * Asm)1633*03ce13f7SAndroid Build Coastguard Worker void Cfg::emitTextHeader(GlobalString Name, GlobalContext *Ctx,
1634*03ce13f7SAndroid Build Coastguard Worker const Assembler *Asm) {
1635*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
1636*03ce13f7SAndroid Build Coastguard Worker return;
1637*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
1638*03ce13f7SAndroid Build Coastguard Worker Str << "\t.text\n";
1639*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getFunctionSections())
1640*03ce13f7SAndroid Build Coastguard Worker Str << "\t.section\t.text." << Name << ",\"ax\",%progbits\n";
1641*03ce13f7SAndroid Build Coastguard Worker if (!Asm->getInternal() || getFlags().getDisableInternal()) {
1642*03ce13f7SAndroid Build Coastguard Worker Str << "\t.globl\t" << Name << "\n";
1643*03ce13f7SAndroid Build Coastguard Worker Str << "\t.type\t" << Name << ",%function\n";
1644*03ce13f7SAndroid Build Coastguard Worker }
1645*03ce13f7SAndroid Build Coastguard Worker Str << "\t" << Asm->getAlignDirective() << " "
1646*03ce13f7SAndroid Build Coastguard Worker << Asm->getBundleAlignLog2Bytes() << ",0x";
1647*03ce13f7SAndroid Build Coastguard Worker for (uint8_t I : Asm->getNonExecBundlePadding())
1648*03ce13f7SAndroid Build Coastguard Worker Str.write_hex(I);
1649*03ce13f7SAndroid Build Coastguard Worker Str << "\n";
1650*03ce13f7SAndroid Build Coastguard Worker Str << Name << ":\n";
1651*03ce13f7SAndroid Build Coastguard Worker }
1652*03ce13f7SAndroid Build Coastguard Worker
emitJumpTables()1653*03ce13f7SAndroid Build Coastguard Worker void Cfg::emitJumpTables() {
1654*03ce13f7SAndroid Build Coastguard Worker switch (getFlags().getOutFileType()) {
1655*03ce13f7SAndroid Build Coastguard Worker case FT_Elf:
1656*03ce13f7SAndroid Build Coastguard Worker case FT_Iasm: {
1657*03ce13f7SAndroid Build Coastguard Worker // The emission needs to be delayed until the after the text section so
1658*03ce13f7SAndroid Build Coastguard Worker // save the offsets in the global context.
1659*03ce13f7SAndroid Build Coastguard Worker for (const InstJumpTable *JumpTable : JumpTables) {
1660*03ce13f7SAndroid Build Coastguard Worker Ctx->addJumpTableData(JumpTable->toJumpTableData(getAssembler()));
1661*03ce13f7SAndroid Build Coastguard Worker }
1662*03ce13f7SAndroid Build Coastguard Worker } break;
1663*03ce13f7SAndroid Build Coastguard Worker case FT_Asm: {
1664*03ce13f7SAndroid Build Coastguard Worker // Emit the assembly directly so we don't need to hang on to all the names
1665*03ce13f7SAndroid Build Coastguard Worker for (const InstJumpTable *JumpTable : JumpTables)
1666*03ce13f7SAndroid Build Coastguard Worker getTarget()->emitJumpTable(this, JumpTable);
1667*03ce13f7SAndroid Build Coastguard Worker } break;
1668*03ce13f7SAndroid Build Coastguard Worker }
1669*03ce13f7SAndroid Build Coastguard Worker }
1670*03ce13f7SAndroid Build Coastguard Worker
emit()1671*03ce13f7SAndroid Build Coastguard Worker void Cfg::emit() {
1672*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
1673*03ce13f7SAndroid Build Coastguard Worker return;
1674*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_emitAsm, this);
1675*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getDecorateAsm()) {
1676*03ce13f7SAndroid Build Coastguard Worker renumberInstructions();
1677*03ce13f7SAndroid Build Coastguard Worker getVMetadata()->init(VMK_Uses);
1678*03ce13f7SAndroid Build Coastguard Worker liveness(Liveness_Basic);
1679*03ce13f7SAndroid Build Coastguard Worker dump("After recomputing liveness for -decorate-asm");
1680*03ce13f7SAndroid Build Coastguard Worker }
1681*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Ctx);
1682*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrEmit();
1683*03ce13f7SAndroid Build Coastguard Worker const Assembler *Asm = getAssembler<>();
1684*03ce13f7SAndroid Build Coastguard Worker
1685*03ce13f7SAndroid Build Coastguard Worker emitTextHeader(FunctionName, Ctx, Asm);
1686*03ce13f7SAndroid Build Coastguard Worker if (getFlags().getDecorateAsm()) {
1687*03ce13f7SAndroid Build Coastguard Worker for (Variable *Var : getVariables()) {
1688*03ce13f7SAndroid Build Coastguard Worker if (Var->hasKnownStackOffset() && !Var->isRematerializable()) {
1689*03ce13f7SAndroid Build Coastguard Worker Str << "\t" << Var->getSymbolicStackOffset() << " = "
1690*03ce13f7SAndroid Build Coastguard Worker << Var->getStackOffset() << "\n";
1691*03ce13f7SAndroid Build Coastguard Worker }
1692*03ce13f7SAndroid Build Coastguard Worker }
1693*03ce13f7SAndroid Build Coastguard Worker }
1694*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
1695*03ce13f7SAndroid Build Coastguard Worker Node->emit(this);
1696*03ce13f7SAndroid Build Coastguard Worker }
1697*03ce13f7SAndroid Build Coastguard Worker emitJumpTables();
1698*03ce13f7SAndroid Build Coastguard Worker Str << "\n";
1699*03ce13f7SAndroid Build Coastguard Worker }
1700*03ce13f7SAndroid Build Coastguard Worker
emitIAS()1701*03ce13f7SAndroid Build Coastguard Worker void Cfg::emitIAS() {
1702*03ce13f7SAndroid Build Coastguard Worker TimerMarker T(TimerStack::TT_emitAsm, this);
1703*03ce13f7SAndroid Build Coastguard Worker // The emitIAS() routines emit into the internal assembler buffer, so there's
1704*03ce13f7SAndroid Build Coastguard Worker // no need to lock the streams.
1705*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes) {
1706*03ce13f7SAndroid Build Coastguard Worker Node->emitIAS(this);
1707*03ce13f7SAndroid Build Coastguard Worker }
1708*03ce13f7SAndroid Build Coastguard Worker emitJumpTables();
1709*03ce13f7SAndroid Build Coastguard Worker }
1710*03ce13f7SAndroid Build Coastguard Worker
getTotalMemoryMB() const1711*03ce13f7SAndroid Build Coastguard Worker size_t Cfg::getTotalMemoryMB() const {
1712*03ce13f7SAndroid Build Coastguard Worker constexpr size_t _1MB = 1024 * 1024;
1713*03ce13f7SAndroid Build Coastguard Worker assert(Allocator != nullptr);
1714*03ce13f7SAndroid Build Coastguard Worker assert(CfgAllocatorTraits::current() == Allocator.get());
1715*03ce13f7SAndroid Build Coastguard Worker return Allocator->getTotalMemory() / _1MB;
1716*03ce13f7SAndroid Build Coastguard Worker }
1717*03ce13f7SAndroid Build Coastguard Worker
getLivenessMemoryMB() const1718*03ce13f7SAndroid Build Coastguard Worker size_t Cfg::getLivenessMemoryMB() const {
1719*03ce13f7SAndroid Build Coastguard Worker constexpr size_t _1MB = 1024 * 1024;
1720*03ce13f7SAndroid Build Coastguard Worker if (Live == nullptr) {
1721*03ce13f7SAndroid Build Coastguard Worker return 0;
1722*03ce13f7SAndroid Build Coastguard Worker }
1723*03ce13f7SAndroid Build Coastguard Worker return Live->getAllocator()->getTotalMemory() / _1MB;
1724*03ce13f7SAndroid Build Coastguard Worker }
1725*03ce13f7SAndroid Build Coastguard Worker
1726*03ce13f7SAndroid Build Coastguard Worker // Dumps the IR with an optional introductory message.
dump(const char * Message)1727*03ce13f7SAndroid Build Coastguard Worker void Cfg::dump(const char *Message) {
1728*03ce13f7SAndroid Build Coastguard Worker if (!BuildDefs::dump())
1729*03ce13f7SAndroid Build Coastguard Worker return;
1730*03ce13f7SAndroid Build Coastguard Worker if (!isVerbose())
1731*03ce13f7SAndroid Build Coastguard Worker return;
1732*03ce13f7SAndroid Build Coastguard Worker OstreamLocker L(Ctx);
1733*03ce13f7SAndroid Build Coastguard Worker Ostream &Str = Ctx->getStrDump();
1734*03ce13f7SAndroid Build Coastguard Worker if (Message[0])
1735*03ce13f7SAndroid Build Coastguard Worker Str << "================ " << Message << " ================\n";
1736*03ce13f7SAndroid Build Coastguard Worker if (isVerbose(IceV_Mem)) {
1737*03ce13f7SAndroid Build Coastguard Worker Str << "Memory size = " << getTotalMemoryMB() << " MB\n";
1738*03ce13f7SAndroid Build Coastguard Worker }
1739*03ce13f7SAndroid Build Coastguard Worker setCurrentNode(getEntryNode());
1740*03ce13f7SAndroid Build Coastguard Worker // Print function name+args
1741*03ce13f7SAndroid Build Coastguard Worker if (isVerbose(IceV_Instructions)) {
1742*03ce13f7SAndroid Build Coastguard Worker Str << "define ";
1743*03ce13f7SAndroid Build Coastguard Worker if (getInternal() && !getFlags().getDisableInternal())
1744*03ce13f7SAndroid Build Coastguard Worker Str << "internal ";
1745*03ce13f7SAndroid Build Coastguard Worker Str << ReturnType << " @" << getFunctionName() << "(";
1746*03ce13f7SAndroid Build Coastguard Worker for (SizeT i = 0; i < Args.size(); ++i) {
1747*03ce13f7SAndroid Build Coastguard Worker if (i > 0)
1748*03ce13f7SAndroid Build Coastguard Worker Str << ", ";
1749*03ce13f7SAndroid Build Coastguard Worker Str << Args[i]->getType() << " ";
1750*03ce13f7SAndroid Build Coastguard Worker Args[i]->dump(this);
1751*03ce13f7SAndroid Build Coastguard Worker }
1752*03ce13f7SAndroid Build Coastguard Worker // Append an extra copy of the function name here, in order to print its
1753*03ce13f7SAndroid Build Coastguard Worker // size stats but not mess up lit tests.
1754*03ce13f7SAndroid Build Coastguard Worker Str << ") { # " << getFunctionNameAndSize() << "\n";
1755*03ce13f7SAndroid Build Coastguard Worker }
1756*03ce13f7SAndroid Build Coastguard Worker resetCurrentNode();
1757*03ce13f7SAndroid Build Coastguard Worker if (isVerbose(IceV_Liveness)) {
1758*03ce13f7SAndroid Build Coastguard Worker // Print summary info about variables
1759*03ce13f7SAndroid Build Coastguard Worker for (Variable *Var : Variables) {
1760*03ce13f7SAndroid Build Coastguard Worker Str << "// multiblock=";
1761*03ce13f7SAndroid Build Coastguard Worker if (getVMetadata()->isTracked(Var))
1762*03ce13f7SAndroid Build Coastguard Worker Str << getVMetadata()->isMultiBlock(Var);
1763*03ce13f7SAndroid Build Coastguard Worker else
1764*03ce13f7SAndroid Build Coastguard Worker Str << "?";
1765*03ce13f7SAndroid Build Coastguard Worker Str << " defs=";
1766*03ce13f7SAndroid Build Coastguard Worker bool FirstPrint = true;
1767*03ce13f7SAndroid Build Coastguard Worker if (VMetadata->getKind() != VMK_Uses) {
1768*03ce13f7SAndroid Build Coastguard Worker if (const Inst *FirstDef = VMetadata->getFirstDefinition(Var)) {
1769*03ce13f7SAndroid Build Coastguard Worker Str << FirstDef->getNumber();
1770*03ce13f7SAndroid Build Coastguard Worker FirstPrint = false;
1771*03ce13f7SAndroid Build Coastguard Worker }
1772*03ce13f7SAndroid Build Coastguard Worker }
1773*03ce13f7SAndroid Build Coastguard Worker if (VMetadata->getKind() == VMK_All) {
1774*03ce13f7SAndroid Build Coastguard Worker for (const Inst *Instr : VMetadata->getLatterDefinitions(Var)) {
1775*03ce13f7SAndroid Build Coastguard Worker if (!FirstPrint)
1776*03ce13f7SAndroid Build Coastguard Worker Str << ",";
1777*03ce13f7SAndroid Build Coastguard Worker Str << Instr->getNumber();
1778*03ce13f7SAndroid Build Coastguard Worker FirstPrint = false;
1779*03ce13f7SAndroid Build Coastguard Worker }
1780*03ce13f7SAndroid Build Coastguard Worker }
1781*03ce13f7SAndroid Build Coastguard Worker Str << " weight=" << Var->getWeight(this) << " ";
1782*03ce13f7SAndroid Build Coastguard Worker Var->dump(this);
1783*03ce13f7SAndroid Build Coastguard Worker Str << " LIVE=" << Var->getLiveRange() << "\n";
1784*03ce13f7SAndroid Build Coastguard Worker }
1785*03ce13f7SAndroid Build Coastguard Worker }
1786*03ce13f7SAndroid Build Coastguard Worker // Print each basic block
1787*03ce13f7SAndroid Build Coastguard Worker for (CfgNode *Node : Nodes)
1788*03ce13f7SAndroid Build Coastguard Worker Node->dump(this);
1789*03ce13f7SAndroid Build Coastguard Worker if (isVerbose(IceV_Instructions))
1790*03ce13f7SAndroid Build Coastguard Worker Str << "}\n";
1791*03ce13f7SAndroid Build Coastguard Worker }
1792*03ce13f7SAndroid Build Coastguard Worker
1793*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
1794