xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceInstVarIter.h (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceInstVarIter.h - Iterate over inst vars ----*- C++ -*-===//
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 Defines a common pattern for iterating over the variables of an
12*03ce13f7SAndroid Build Coastguard Worker /// instruction.
13*03ce13f7SAndroid Build Coastguard Worker ///
14*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
15*03ce13f7SAndroid Build Coastguard Worker 
16*03ce13f7SAndroid Build Coastguard Worker #ifndef SUBZERO_SRC_ICEINSTVARITER_H
17*03ce13f7SAndroid Build Coastguard Worker #define SUBZERO_SRC_ICEINSTVARITER_H
18*03ce13f7SAndroid Build Coastguard Worker 
19*03ce13f7SAndroid Build Coastguard Worker /// In Subzero, an Instr may have multiple Ice::Operands, and each Operand can
20*03ce13f7SAndroid Build Coastguard Worker /// have zero, one, or more Variables.
21*03ce13f7SAndroid Build Coastguard Worker ///
22*03ce13f7SAndroid Build Coastguard Worker /// We found that a common pattern in Subzero is to iterate over all the
23*03ce13f7SAndroid Build Coastguard Worker /// Variables in an Instruction. This led to the following pattern being
24*03ce13f7SAndroid Build Coastguard Worker /// repeated multiple times across the codebase:
25*03ce13f7SAndroid Build Coastguard Worker ///
26*03ce13f7SAndroid Build Coastguard Worker /// for (Operand Op : Instr.Operands())
27*03ce13f7SAndroid Build Coastguard Worker ///   for (Variable Var : Op.Vars())
28*03ce13f7SAndroid Build Coastguard Worker ///     do_my_thing(Var, Instr)
29*03ce13f7SAndroid Build Coastguard Worker ///
30*03ce13f7SAndroid Build Coastguard Worker ///
31*03ce13f7SAndroid Build Coastguard Worker /// This code is straightforward, but one may take a couple of seconds to
32*03ce13f7SAndroid Build Coastguard Worker /// identify what it is doing. We therefore introduce a macroized iterator for
33*03ce13f7SAndroid Build Coastguard Worker /// hiding this common idiom behind a more explicit interface.
34*03ce13f7SAndroid Build Coastguard Worker ///
35*03ce13f7SAndroid Build Coastguard Worker /// FOREACH_VAR_IN_INST(Var, Instr) provides this interface. Its first argument
36*03ce13f7SAndroid Build Coastguard Worker /// needs to be a valid C++ identifier currently undeclared in the current
37*03ce13f7SAndroid Build Coastguard Worker /// scope; Instr can be any expression yielding a Ice::Inst&&. Even though its
38*03ce13f7SAndroid Build Coastguard Worker /// definition is ugly, awful, painful-to-read, using it is fairly simple:
39*03ce13f7SAndroid Build Coastguard Worker ///
40*03ce13f7SAndroid Build Coastguard Worker /// FOREACH_VAR_IN_INST(Var, Instr)
41*03ce13f7SAndroid Build Coastguard Worker ///   do_my_thing(Var, Instr)
42*03ce13f7SAndroid Build Coastguard Worker ///
43*03ce13f7SAndroid Build Coastguard Worker /// If your loop body contains more than one statement, you can wrap it with a
44*03ce13f7SAndroid Build Coastguard Worker /// {}, just like any other C++ statement. Note that doing
45*03ce13f7SAndroid Build Coastguard Worker ///
46*03ce13f7SAndroid Build Coastguard Worker /// FOREACH_VAR_IN_INST(Var0, Instr0)
47*03ce13f7SAndroid Build Coastguard Worker ///   FOREACH_VAR_IN_INST(Var1, Instr1)
48*03ce13f7SAndroid Build Coastguard Worker ///
49*03ce13f7SAndroid Build Coastguard Worker /// is perfectly safe and legal -- as long as Var0 and Var1 are different
50*03ce13f7SAndroid Build Coastguard Worker /// identifiers.
51*03ce13f7SAndroid Build Coastguard Worker ///
52*03ce13f7SAndroid Build Coastguard Worker /// It is sometimes useful to know Var's index in Instr, which can be obtained
53*03ce13f7SAndroid Build Coastguard Worker /// with
54*03ce13f7SAndroid Build Coastguard Worker ///
55*03ce13f7SAndroid Build Coastguard Worker /// IndexOfVarInInst(Var)
56*03ce13f7SAndroid Build Coastguard Worker ///
57*03ce13f7SAndroid Build Coastguard Worker /// Similarly, the current Variable's Operand index can be obtained with
58*03ce13f7SAndroid Build Coastguard Worker ///
59*03ce13f7SAndroid Build Coastguard Worker /// IndexOfVarOperandInInst(Var).
60*03ce13f7SAndroid Build Coastguard Worker ///
61*03ce13f7SAndroid Build Coastguard Worker /// And that's pretty much it. Now, if you really hate yourself, keep reading,
62*03ce13f7SAndroid Build Coastguard Worker /// but beware! The iterator implementation abuses comma operators, for
63*03ce13f7SAndroid Build Coastguard Worker /// statements, variable initialization and expression evaluations. You have
64*03ce13f7SAndroid Build Coastguard Worker /// been warned.
65*03ce13f7SAndroid Build Coastguard Worker ///
66*03ce13f7SAndroid Build Coastguard Worker /// **Implementation details**
67*03ce13f7SAndroid Build Coastguard Worker ///
68*03ce13f7SAndroid Build Coastguard Worker /// First, let's "break" the two loops into multiple parts:
69*03ce13f7SAndroid Build Coastguard Worker ///
70*03ce13f7SAndroid Build Coastguard Worker /// for ( Init1; Cond1; Step1 )
71*03ce13f7SAndroid Build Coastguard Worker ///   if ( CondIf )
72*03ce13f7SAndroid Build Coastguard Worker ///     UnreachableThenBody
73*03ce13f7SAndroid Build Coastguard Worker ///   else
74*03ce13f7SAndroid Build Coastguard Worker ///     for ( Init2; Cond2; Step2 )
75*03ce13f7SAndroid Build Coastguard Worker ///
76*03ce13f7SAndroid Build Coastguard Worker /// The hairiest, scariest, most confusing parts here are Init2 and Cond2, so
77*03ce13f7SAndroid Build Coastguard Worker /// let's save them for later.
78*03ce13f7SAndroid Build Coastguard Worker ///
79*03ce13f7SAndroid Build Coastguard Worker ///  1) Init1 declares five integer variables:
80*03ce13f7SAndroid Build Coastguard Worker ///      * i          --> outer loop control variable;
81*03ce13f7SAndroid Build Coastguard Worker ///      * Var##Index --> the current variable index
82*03ce13f7SAndroid Build Coastguard Worker ///      * SrcSize    --> how many operands does Instr have?
83*03ce13f7SAndroid Build Coastguard Worker ///      * j          --> the inner loop control variable
84*03ce13f7SAndroid Build Coastguard Worker ///      * NumVars    --> how many variables does the current operand have?
85*03ce13f7SAndroid Build Coastguard Worker ///
86*03ce13f7SAndroid Build Coastguard Worker ///  2) Cond1 and Step1 are your typical for condition and step expressions.
87*03ce13f7SAndroid Build Coastguard Worker ///
88*03ce13f7SAndroid Build Coastguard Worker ///  3) CondIf is where the voodoo starts. We abuse CondIf to declare a local
89*03ce13f7SAndroid Build Coastguard Worker ///  Operand * variable to hold the current operand being evaluated to avoid
90*03ce13f7SAndroid Build Coastguard Worker ///  invoking an Instr::getOperand for each outter loop iteration -- which
91*03ce13f7SAndroid Build Coastguard Worker ///  caused a small performance regression. We initialize the Operand *
92*03ce13f7SAndroid Build Coastguard Worker ///  variable with nullptr, so UnreachableThenBody is trully unreachable, and
93*03ce13f7SAndroid Build Coastguard Worker ///  use the else statement to declare the inner loop. We want to use an else
94*03ce13f7SAndroid Build Coastguard Worker ///  here to prevent code like
95*03ce13f7SAndroid Build Coastguard Worker ///
96*03ce13f7SAndroid Build Coastguard Worker ///      FOREACH_VAR_IN_INST(Var, Instr) {
97*03ce13f7SAndroid Build Coastguard Worker ///      } else {
98*03ce13f7SAndroid Build Coastguard Worker ///      }
99*03ce13f7SAndroid Build Coastguard Worker ///
100*03ce13f7SAndroid Build Coastguard Worker ///  from being legal. We also want to avoid warnings about "dangling else"s.
101*03ce13f7SAndroid Build Coastguard Worker ///
102*03ce13f7SAndroid Build Coastguard Worker ///  4) Init2 is where the voodoo starts. It declares a Variable * local
103*03ce13f7SAndroid Build Coastguard Worker ///  variable name 'Var' (i.e., whatever identifier the first parameter to
104*03ce13f7SAndroid Build Coastguard Worker ///  FOREACH_VAR_IN_INST is), and initializes it with nullptr. Why nullptr?
105*03ce13f7SAndroid Build Coastguard Worker ///  Because as stated above, some operands have zero Variables, and therefore
106*03ce13f7SAndroid Build Coastguard Worker ///  initializing Var = CurrentOperand->Variable(0) would lead to an assertion.
107*03ce13f7SAndroid Build Coastguard Worker ///  Init2 is also required to initialize the control variables used in Cond2,
108*03ce13f7SAndroid Build Coastguard Worker ///  as well as the current Operand * holder,  Therefore, we use the obscure
109*03ce13f7SAndroid Build Coastguard Worker ///  comma operator to initialize Var, and the control variables. The
110*03ce13f7SAndroid Build Coastguard Worker ///  declaration
111*03ce13f7SAndroid Build Coastguard Worker ///
112*03ce13f7SAndroid Build Coastguard Worker ///      Variable *Var = (j = 0, CurrentOperand = Instr.Operand[i],
113*03ce13f7SAndroid Build Coastguard Worker ///                       NumVars = CurrentOperand.NumVars, nullptr)
114*03ce13f7SAndroid Build Coastguard Worker ///
115*03ce13f7SAndroid Build Coastguard Worker ///  achieves that.
116*03ce13f7SAndroid Build Coastguard Worker ///
117*03ce13f7SAndroid Build Coastguard Worker ///  5) Cond2 is where we lose all hopes of having a self-documenting
118*03ce13f7SAndroid Build Coastguard Worker ///  implementation. The stop condition for the inner loop is simply
119*03ce13f7SAndroid Build Coastguard Worker ///
120*03ce13f7SAndroid Build Coastguard Worker ///      j < NumVars
121*03ce13f7SAndroid Build Coastguard Worker ///
122*03ce13f7SAndroid Build Coastguard Worker ///  But there is one more thing we need to do before jumping to the iterator's
123*03ce13f7SAndroid Build Coastguard Worker ///  body: we need to initialize Var with the current variable, but only if the
124*03ce13f7SAndroid Build Coastguard Worker ///  loop has not terminated. So we implemented Cond2 in a way that it would
125*03ce13f7SAndroid Build Coastguard Worker ///  make Var point to the current Variable, but only if there were more
126*03ce13f7SAndroid Build Coastguard Worker ///  variables. So Cond2 became:
127*03ce13f7SAndroid Build Coastguard Worker ///
128*03ce13f7SAndroid Build Coastguard Worker ///      j < NumVars && (Var = CurrentOperand.Var[j])
129*03ce13f7SAndroid Build Coastguard Worker ///
130*03ce13f7SAndroid Build Coastguard Worker ///  which is not quite right. Cond2 would evaluate to false if
131*03ce13f7SAndroid Build Coastguard Worker ///  CurrentOperand.Var[j] == nullptr. Even though that should never happen in
132*03ce13f7SAndroid Build Coastguard Worker ///  Subzero, assuming this is always true is dangerous and could lead to
133*03ce13f7SAndroid Build Coastguard Worker ///  problems in the future. So we abused the comma operator one more time here:
134*03ce13f7SAndroid Build Coastguard Worker ///
135*03ce13f7SAndroid Build Coastguard Worker ///      j < NumVars && ((Var = CurrentOperand.Var[j]), true)
136*03ce13f7SAndroid Build Coastguard Worker ///
137*03ce13f7SAndroid Build Coastguard Worker ///  this expression will evaluate to true if, and only if, j < NumVars.
138*03ce13f7SAndroid Build Coastguard Worker ///
139*03ce13f7SAndroid Build Coastguard Worker ///  6) Step2 increments the inner loop's control variable, as well as the
140*03ce13f7SAndroid Build Coastguard Worker ///  current variable index.
141*03ce13f7SAndroid Build Coastguard Worker ///
142*03ce13f7SAndroid Build Coastguard Worker /// We use Var -- which should be a valid C++ identifier -- to uniquify names
143*03ce13f7SAndroid Build Coastguard Worker /// -- e.g., i##Var instead of simply i because we want users to be able to use
144*03ce13f7SAndroid Build Coastguard Worker /// the iterator for cross-products involving instructions' variables.
145*03ce13f7SAndroid Build Coastguard Worker #define FOREACH_VAR_IN_INST(Var, Instr)                                        \
146*03ce13f7SAndroid Build Coastguard Worker   for (SizeT Sz_I##Var##_ = 0, Sz_##Var##Index_ = 0,                           \
147*03ce13f7SAndroid Build Coastguard Worker              Sz_SrcSize##Var##_ = (Instr).getSrcSize(), Sz_J##Var##_ = 0,      \
148*03ce13f7SAndroid Build Coastguard Worker              Sz_NumVars##Var##_ = 0, Sz_Foreach_Break = 0;                     \
149*03ce13f7SAndroid Build Coastguard Worker        !Sz_Foreach_Break && Sz_I##Var##_ < Sz_SrcSize##Var##_; ++Sz_I##Var##_) \
150*03ce13f7SAndroid Build Coastguard Worker     if (Operand *Sz_Op##Var##_ = nullptr)                                      \
151*03ce13f7SAndroid Build Coastguard Worker       /*nothing*/;                                                             \
152*03ce13f7SAndroid Build Coastguard Worker     else                                                                       \
153*03ce13f7SAndroid Build Coastguard Worker       for (Variable *Var =                                                     \
154*03ce13f7SAndroid Build Coastguard Worker                (Sz_J##Var##_ = 0,                                              \
155*03ce13f7SAndroid Build Coastguard Worker                Sz_Op##Var##_ = (Instr).getSrc(Sz_I##Var##_),                   \
156*03ce13f7SAndroid Build Coastguard Worker                Sz_NumVars##Var##_ = Sz_Op##Var##_->getNumVars(), nullptr);     \
157*03ce13f7SAndroid Build Coastguard Worker            !Sz_Foreach_Break && Sz_J##Var##_ < Sz_NumVars##Var##_ &&           \
158*03ce13f7SAndroid Build Coastguard Worker            ((Var = Sz_Op##Var##_->getVar(Sz_J##Var##_)), true);                \
159*03ce13f7SAndroid Build Coastguard Worker            ++Sz_J##Var##_, ++Sz_##Var##Index_)
160*03ce13f7SAndroid Build Coastguard Worker 
161*03ce13f7SAndroid Build Coastguard Worker #define IsOnlyValidInFOREACH_VAR_IN_INST(V)                                    \
162*03ce13f7SAndroid Build Coastguard Worker   (static_cast<const SizeT>(Sz_##V##_))
163*03ce13f7SAndroid Build Coastguard Worker #define IndexOfVarInInst(Var) IsOnlyValidInFOREACH_VAR_IN_INST(Var##Index)
164*03ce13f7SAndroid Build Coastguard Worker #define IndexOfVarOperandInInst(Var) IsOnlyValidInFOREACH_VAR_IN_INST(I##Var)
165*03ce13f7SAndroid Build Coastguard Worker #define FOREACH_VAR_IN_INST_BREAK                                              \
166*03ce13f7SAndroid Build Coastguard Worker   if (true) {                                                                  \
167*03ce13f7SAndroid Build Coastguard Worker     Sz_Foreach_Break = 1;                                                      \
168*03ce13f7SAndroid Build Coastguard Worker     continue;                                                                  \
169*03ce13f7SAndroid Build Coastguard Worker   } else {                                                                     \
170*03ce13f7SAndroid Build Coastguard Worker   }
171*03ce13f7SAndroid Build Coastguard Worker #undef OnlyValidIn_FOREACH_VAR_IN_INSTS
172*03ce13f7SAndroid Build Coastguard Worker 
173*03ce13f7SAndroid Build Coastguard Worker #endif // SUBZERO_SRC_ICEINSTVARITER_H
174