Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 //===- subzero/src/IceInstVarIter.h - Iterate over inst vars-----*- C++ -*-===// | |
|
Jim Stichnoth
2015/08/29 23:20:39
s/vars-/vars /
John
2015/08/31 16:26:39
Done.
| |
| 2 // | |
| 3 // The Subzero Code Generator | |
| 4 // | |
| 5 // This file is distributed under the University of Illinois Open Source | |
| 6 // License. See LICENSE.TXT for details. | |
| 7 // | |
| 8 //===----------------------------------------------------------------------===// | |
| 9 /// | |
| 10 /// \file | |
| 11 /// This file defines a common pattern for iterating over the variables of an | |
| 12 /// instruction. | |
| 13 /// | |
| 14 //===----------------------------------------------------------------------===// | |
| 15 | |
| 16 #ifndef SUBZERO_SRC_ICEINSTVARITER_H | |
| 17 #define SUBZERO_SRC_ICEINSTVARITER_H | |
| 18 | |
| 19 /// In Subzero, an Instr may have multiple Ice::Operands, and each Operand can | |
| 20 /// have zero, one, or more Variables. | |
| 21 /// | |
| 22 /// We found that a common pattern in Subzero is to iterate over all the | |
| 23 /// Variables in an Instruction. This lead to the following pattern being | |
|
Jim Stichnoth
2015/08/29 23:20:39
leads or led
John
2015/08/31 16:26:39
Done.
| |
| 24 /// repeated multiple times across the codebase: | |
| 25 /// | |
| 26 /// for (Operand Op : Instr.Operands()) | |
| 27 /// for (Variable Var : Op.Vars()) | |
| 28 /// do_my_thing(Var, Instr) | |
| 29 /// | |
| 30 /// | |
| 31 /// This code is straightforward, but one may take a couple of seconds to | |
| 32 /// identify what it is doing. We therefore introduce a macroized iterator for | |
| 33 /// hiding this common idiom behind a more explicit interface. | |
| 34 /// | |
| 35 /// FOREACH_VAR_IN_INST(Var, Instr) provides this interface. Its first argument | |
| 36 /// needs to be a valid C++ identifier currently undeclared in the current | |
| 37 /// scope; Instr can be any expression yielding a Ice::Inst&&. Even though its | |
| 38 /// definition is ugly, awful, painful-to-read, using it is fairly simple: | |
|
ascull
2015/08/31 16:30:21
Why no use a function for this and pass in a lambd
John
2015/08/31 17:43:09
I am all for avoiding macros/macro-trickery and ot
| |
| 39 /// | |
| 40 /// FOREACH_VAR_IN_INST(Var, Instr) | |
| 41 /// do_my_thing(Var, Instr) | |
| 42 /// | |
| 43 /// If your loop body contains more than one statement, you can wrap it with a | |
| 44 /// {}, just like any other C++ statement. Note that doing | |
| 45 /// | |
| 46 /// FOREACH_VAR_IN_INST(Var0, Instr0) | |
| 47 /// FOREACH_VAR_IN_INST(Var1, Instr1) | |
| 48 /// | |
| 49 /// is perfectly safe and legal -- as long as Var0 and Var1 are different | |
| 50 /// identifiers. | |
| 51 /// | |
| 52 /// It is sometimes useful to know Var's index in Instr, which can be obtained | |
| 53 /// with | |
| 54 /// | |
| 55 /// IndexOfVarInInst(Var) | |
| 56 /// | |
| 57 /// Similarly, the current Variable's Operand index can be obtained with | |
| 58 /// | |
| 59 /// IndexOfVarOperandInInst(Var). | |
| 60 /// | |
| 61 /// And that's pretty much it. Now, if you really hate yourself, keep reading, | |
| 62 /// but beware! The iterator implementation abuses comma operators, for | |
| 63 /// statements, variable initialization and expression evaluations. You have | |
| 64 /// been warned. | |
| 65 /// | |
| 66 /// **Implementation details** | |
| 67 /// | |
| 68 /// First, let's "break" the two loops into multiple parts: | |
| 69 /// | |
| 70 /// for ( Init1; Cond1; Step1 ) | |
| 71 /// for ( Init2; Cond2; Step2 ) | |
| 72 /// | |
| 73 /// The hariest, scariest, most confusing parts here are Init2 and Cond2, so | |
|
Jim Stichnoth
2015/08/29 23:20:39
hairiest
John
2015/08/31 16:26:39
Done.
| |
| 74 /// let's save them for later. | |
| 75 /// | |
| 76 /// 1) Init1 declares five integer variables: | |
| 77 /// * i --> outer loop control variable; | |
| 78 /// * Var##Index --> the current variable index | |
| 79 /// * SrcSize --> how many operands does Instr have? | |
| 80 /// * j --> the inner loop control variable | |
| 81 /// * NumVars --> how many variables does the current operand have? | |
| 82 /// | |
| 83 /// 2) Cond1 and Step1 are your typical for condition and step expressions. | |
| 84 /// | |
| 85 /// 3) Init2 is where the voodoo starts. It declares a Variable * local | |
| 86 /// variable name 'Var' (i.e., whatever identifier the first parameter to | |
| 87 /// FOREACH_VAR_IN_INST is), and initialize it with nullptr. Why nullptr? | |
|
Jim Stichnoth
2015/08/29 23:20:39
initializes
John
2015/08/31 16:26:39
Done.
| |
| 88 /// Because as stated above, some operands have zero Variables, and therefore | |
| 89 /// initializing Var = CurrentOperand->Variable(0) would lead to an assertion. | |
| 90 /// Init2 is also required to initialize the control variables used in Cond2. | |
| 91 /// Therefore, we use the obscure comma operator to initialize Var, and the | |
| 92 /// control variables. The declaration | |
| 93 /// | |
| 94 /// Variable *Var = (j = 0, NumVars = CurrentOperand.NumVars, nullptr) | |
| 95 /// | |
| 96 /// achieves that. | |
| 97 /// | |
| 98 /// 4) Cond2 is where we lose all hopes of having a self-documenting | |
| 99 /// implementation. The stop condition for the inner loop is simply | |
| 100 /// | |
| 101 /// j < NumVars | |
| 102 /// | |
| 103 /// But there is one more thing we need to do before jumping to the iterators | |
|
Jim Stichnoth
2015/08/29 23:20:39
iterator's
John
2015/08/31 16:26:40
Done.
| |
| 104 /// body: we need to initialize Var with the current variable, but only if the | |
| 105 /// loop has not terminated. So we implemented Cond2 in a way that it would | |
| 106 /// make | |
|
Jim Stichnoth
2015/08/29 23:20:39
weird line breaks
John
2015/08/31 16:26:39
Done.
| |
| 107 /// Var point to the current Variable, but only if there were more variables. | |
| 108 /// So | |
| 109 /// Cond2 became: | |
| 110 /// | |
| 111 /// j < NumVars && (Var = CurrentOperand.Var[j]) | |
| 112 /// | |
| 113 /// which is not quite right. Cond2 would evalute to false if | |
| 114 /// CurrentOperand.Var[j] == nullptr. Even though that should never happen in | |
| 115 /// Subzero, assuming this is always true is dangerous and could lead to | |
|
Jim Stichnoth
2015/08/29 23:20:39
It is in fact safe to assume that in Subzero.
But
John
2015/08/31 16:26:39
Acknowledged.
| |
| 116 /// problems | |
| 117 /// in the future. So we abused the comma operator one more time here: | |
| 118 /// | |
| 119 /// j < NumVars && ((Var = CurrentOperand.Var[j]), true) | |
| 120 /// | |
| 121 /// this expression will evaluate to true if, and only if, j < NumVars. | |
| 122 /// | |
| 123 /// 5) Step2 increments the inner loop's control variable, as well as the | |
| 124 /// current variable index. | |
| 125 /// | |
| 126 /// We use Var -- which should be a valid C++ identifier -- to uniquefy names -- | |
|
Jim Stichnoth
2015/08/29 23:20:39
I think uniquify is the more common spelling of th
John
2015/08/31 16:26:39
Done.
| |
| 127 /// e.g., i##Var instead of simply i because we want users to be able to use the | |
| 128 /// iterator for cross-products involving instructions' variables. | |
| 129 #define FOREACH_VAR_IN_INST(Var, Instr) \ | |
| 130 for (SizeT ___I##Var##___ = 0, ___##Var##Index##___ = 0, \ | |
|
Jim Stichnoth
2015/08/29 23:20:39
I looked more closely at C++ reserved identifiers,
John
2015/08/31 16:26:39
Done.
Jim Stichnoth
2015/08/31 18:22:21
Not quite. You're not allowed to start the identi
ascull
2015/08/31 18:33:52
http://en.cppreference.com/w/cpp/language/identifi
| |
| 131 ___SrcSize##Var##___ = (Instr).getSrcSize(), ___J##Var##___ = 0, \ | |
| 132 ___NumVars##Var##___ = 0; \ | |
| 133 ___I##Var##___ < ___SrcSize##Var##___; ++___I##Var##___) \ | |
| 134 for (Variable *Var = (___J##Var##___ = 0, \ | |
| 135 ___NumVars##Var##___ = \ | |
| 136 (Instr).getSrc(___I##Var##___)->getNumVars(), \ | |
| 137 nullptr); \ | |
| 138 ___J##Var##___ < ___NumVars##Var##___ && \ | |
| 139 ((Var = (Instr).getSrc(___I##Var##___)->getVar(___J##Var##___)), \ | |
| 140 true); \ | |
| 141 ++___J##Var##___, ++___##Var##Index___) | |
| 142 | |
| 143 #define IndexOfVarInInst(Var) ((const SizeT)___##Var##Index##___) | |
|
Jim Stichnoth
2015/08/29 23:20:39
I wonder if we could find good names for the three
John
2015/08/31 16:26:39
I am not a huge fan of prefixes/suffixes as I find
Jim Stichnoth
2015/08/31 18:22:21
Sick. :)
| |
| 144 #define IndexOfVarOperandInInst(Var) ((const SizeT)___I##Var##___) | |
| 145 | |
| 146 #endif // SUBZERO_SRC_ICEINSTVARITER_H | |
| OLD | NEW |