@@ -41,6 +41,13 @@ struct OutlinableGroup {
41
41
// / Flag for whether we should not consider this group of OutlinableRegions
42
42
// / for extraction.
43
43
bool IgnoreGroup = false ;
44
+
45
+ // / For the \ref Regions, we look at every Value. If it is a constant,
46
+ // / we check whether it is the same in Region.
47
+ // /
48
+ // / \param [in,out] NotSame contains the global value numbers where the
49
+ // / constant is not always the same, and must be passed in as an argument.
50
+ void findSameConstants (DenseSet<unsigned > &NotSame);
44
51
};
45
52
46
53
// / Move the contents of \p SourceBB to before the last instruction of \p
@@ -144,6 +151,198 @@ void OutlinableRegion::reattachCandidate() {
144
151
CandidateSplit = false ;
145
152
}
146
153
154
+ // / Find whether \p V matches the Constants previously found for the \p GVN.
155
+ // /
156
+ // / \param V - The value to check for consistency.
157
+ // / \param GVN - The global value number assigned to \p V.
158
+ // / \param GVNToConstant - The mapping of global value number to Constants.
159
+ // / \returns true if the Value matches the Constant mapped to by V and false if
160
+ // / it \p V is a Constant but does not match.
161
+ // / \returns None if \p V is not a Constant.
162
+ static Optional<bool >
163
+ constantMatches (Value *V, unsigned GVN,
164
+ DenseMap<unsigned , Constant *> &GVNToConstant) {
165
+ // See if we have a constants
166
+ Constant *CST = dyn_cast<Constant>(V);
167
+ if (!CST)
168
+ return None;
169
+
170
+ // Holds a mapping from a global value number to a Constant.
171
+ DenseMap<unsigned , Constant *>::iterator GVNToConstantIt;
172
+ bool Inserted;
173
+
174
+ // If we have a constant, try to make a new entry in the GVNToConstant.
175
+ std::tie (GVNToConstantIt, Inserted) =
176
+ GVNToConstant.insert (std::make_pair (GVN, CST));
177
+ // If it was found and is not equal, it is not the same. We do not
178
+ // handle this case yet, and exit early.
179
+ if (Inserted || (GVNToConstantIt->second == CST))
180
+ return true ;
181
+
182
+ return false ;
183
+ }
184
+
185
+ // / Find whether \p Region matches the global value numbering to Constant mapping
186
+ // / found so far.
187
+ // /
188
+ // / \param Region - The OutlinableRegion we are checking for constants
189
+ // / \param NotSame - The set of global value numbers that do not have the same
190
+ // / constant in each region.
191
+ // / \returns true if all Constants are the same in every use of a Constant in \p
192
+ // / Region and false if not
193
+ static bool
194
+ collectRegionsConstants (OutlinableRegion &Region,
195
+ DenseMap<unsigned , Constant *> &GVNToConstant,
196
+ DenseSet<unsigned > &NotSame) {
197
+ IRSimilarityCandidate &C = *Region.Candidate ;
198
+ for (IRInstructionData &ID : C) {
199
+
200
+ // Iterate over the operands in an instruction. If the global value number,
201
+ // assigned by the IRSimilarityCandidate, has been seen before, we check if
202
+ // the the number has been found to be not the same value in each instance.
203
+ for (Value *V : ID.OperVals ) {
204
+ Optional<unsigned > GVNOpt = C.getGVN (V);
205
+ assert (GVNOpt.hasValue () && " Expected a GVN for operand?" );
206
+ unsigned GVN = GVNOpt.getValue ();
207
+
208
+ // If this global value has been found to not be the same, it could have
209
+ // just been a register, check that it is not a constant value.
210
+ if (NotSame.find (GVN) != NotSame.end ()) {
211
+ if (isa<Constant>(V))
212
+ return false ;
213
+ continue ;
214
+ }
215
+
216
+ // If it has been the same so far, we check the value for if the
217
+ // associated Constant value match the previous instances of the same
218
+ // global value number. If the global value does not map to a Constant,
219
+ // it is considered to not be the same value.
220
+ Optional<bool > ConstantMatches = constantMatches (V, GVN, GVNToConstant);
221
+ if (ConstantMatches.hasValue ()) {
222
+ if (ConstantMatches.getValue ())
223
+ continue ;
224
+ else
225
+ return false ;
226
+ }
227
+
228
+ // While this value is a register, it might not have been previously,
229
+ // make sure we don't already have a constant mapped to this global value
230
+ // number.
231
+ if (GVNToConstant.find (GVN) != GVNToConstant.end ())
232
+ return false ;
233
+
234
+ NotSame.insert (GVN);
235
+ }
236
+ }
237
+
238
+ return true ;
239
+ }
240
+
241
+ void OutlinableGroup::findSameConstants (DenseSet<unsigned > &NotSame) {
242
+ DenseMap<unsigned , Constant *> GVNToConstant;
243
+
244
+ for (OutlinableRegion *Region : Regions)
245
+ if (!collectRegionsConstants (*Region, GVNToConstant, NotSame)) {
246
+ IgnoreGroup = true ;
247
+ return ;
248
+ }
249
+ }
250
+
251
+ // / Find the GVN for the inputs that have been found by the CodeExtractor,
252
+ // / excluding the ones that will be removed by llvm.assumes as these will be
253
+ // / removed by the CodeExtractor.
254
+ // /
255
+ // / \param [in] C - The IRSimilarityCandidate containing the region we are
256
+ // / analyzing.
257
+ // / \param [in] CurrentInputs - The set of inputs found by the
258
+ // / CodeExtractor.
259
+ // / \param [out] CurrentInputNumbers - The global value numbers for the extracted
260
+ // / arguments.
261
+ static void mapInputsToGVNs (IRSimilarityCandidate &C,
262
+ SetVector<Value *> &CurrentInputs,
263
+ std::vector<unsigned > &EndInputNumbers) {
264
+ // Get the global value number for each input.
265
+ for (Value *Input : CurrentInputs) {
266
+ assert (Input && " Have a nullptr as an input" );
267
+ assert (C.getGVN (Input).hasValue () &&
268
+ " Could not find a numbering for the given input" );
269
+ EndInputNumbers.push_back (C.getGVN (Input).getValue ());
270
+ }
271
+ }
272
+
273
+ // / Find the input GVNs and the output values for a region of Instructions.
274
+ // / Using the code extractor, we collect the inputs to the extracted function.
275
+ // /
276
+ // / The \p Region can be identifed as needing to be ignored in this function.
277
+ // / It should be checked whether it should be ignored after a call to this
278
+ // / function.
279
+ // /
280
+ // / \param [in,out] Region - The region of code to be analyzed.
281
+ // / \param [out] Inputs - The global value numbers for the extracted arguments.
282
+ // / \param [out] ArgInputs - The values of the inputs to the extracted function.
283
+ static void getCodeExtractorArguments (OutlinableRegion &Region,
284
+ std::vector<unsigned > &InputGVNs,
285
+ SetVector<Value *> &ArgInputs) {
286
+ IRSimilarityCandidate &C = *Region.Candidate ;
287
+
288
+ // OverallInputs are the inputs to the region found by the CodeExtractor,
289
+ // SinkCands and HoistCands are used by the CodeExtractor to find sunken
290
+ // allocas of values whose lifetimes are contained completely within the
291
+ // outlined region. Outputs are values used outside of the outlined region
292
+ // found by the CodeExtractor.
293
+ SetVector<Value *> OverallInputs, SinkCands, HoistCands, Outputs;
294
+
295
+ // Use the code extractor to get the inputs and outputs, without sunken
296
+ // allocas or removing llvm.assumes.
297
+ CodeExtractor *CE = Region.CE ;
298
+ CE->findInputsOutputs (OverallInputs, Outputs, SinkCands);
299
+ assert (Region.StartBB && " Region must have a start BasicBlock!" );
300
+ Function *OrigF = Region.StartBB ->getParent ();
301
+ CodeExtractorAnalysisCache CEAC (*OrigF);
302
+ BasicBlock *Dummy = nullptr ;
303
+
304
+ // The region may be ineligible due to VarArgs in the parent function. In this
305
+ // case we ignore the region.
306
+ if (!CE->isEligible ()) {
307
+ Region.IgnoreRegion = true ;
308
+ return ;
309
+ }
310
+
311
+ // Find if any values are going to be sunk into the function when extracted
312
+ CE->findAllocas (CEAC, SinkCands, HoistCands, Dummy);
313
+ CE->findInputsOutputs (ArgInputs, Outputs, SinkCands);
314
+
315
+ // TODO: Support regions with output values. Outputs add an extra layer of
316
+ // resolution that adds too much complexity at this stage.
317
+ if (Outputs.size () > 0 ) {
318
+ Region.IgnoreRegion = true ;
319
+ return ;
320
+ }
321
+
322
+ // TODO: Support regions with sunken allocas: values whose lifetimes are
323
+ // contained completely within the outlined region. These are not guaranteed
324
+ // to be the same in every region, so we must elevate them all to arguments
325
+ // when they appear. If these values are not equal, it means there is some
326
+ // Input in OverallInputs that was removed for ArgInputs.
327
+ if (ArgInputs.size () != OverallInputs.size ()) {
328
+ Region.IgnoreRegion = true ;
329
+ return ;
330
+ }
331
+
332
+ mapInputsToGVNs (C, OverallInputs, InputGVNs);
333
+ }
334
+
335
+ void IROutliner::findAddInputsOutputs (
336
+ Module &M, OutlinableRegion &Region) {
337
+ std::vector<unsigned > Inputs;
338
+ SetVector<Value *> ArgInputs;
339
+
340
+ getCodeExtractorArguments (Region, Inputs, ArgInputs);
341
+
342
+ if (Region.IgnoreRegion )
343
+ return ;
344
+ }
345
+
147
346
void IROutliner::pruneIncompatibleRegions (
148
347
std::vector<IRSimilarityCandidate> &CandidateVec,
149
348
OutlinableGroup &CurrentGroup) {
@@ -271,6 +470,7 @@ unsigned IROutliner::doOutline(Module &M) {
271
470
RHS[0 ].getLength () * RHS.size ();
272
471
});
273
472
473
+ DenseSet<unsigned > NotSame;
274
474
// Iterate over the possible sets of similarity.
275
475
for (SimilarityGroup &CandidateVec : SimilarityCandidates) {
276
476
OutlinableGroup CurrentGroup;
@@ -284,7 +484,18 @@ unsigned IROutliner::doOutline(Module &M) {
284
484
if (CurrentGroup.Regions .size () < 2 )
285
485
continue ;
286
486
287
- // Create a CodeExtractor for each outlinable region.
487
+ // Determine if there are any values that are the same constant throughout
488
+ // each section in the set.
489
+ NotSame.clear ();
490
+ CurrentGroup.findSameConstants (NotSame);
491
+
492
+ if (CurrentGroup.IgnoreGroup )
493
+ continue ;
494
+
495
+ // Create a CodeExtractor for each outlinable region. Identify inputs and
496
+ // outputs for each section using the code extractor and create the argument
497
+ // types for the Aggregate Outlining Function.
498
+ std::vector<OutlinableRegion *> OutlinedRegions;
288
499
for (OutlinableRegion *OS : CurrentGroup.Regions ) {
289
500
// Break the outlinable region out of its parent BasicBlock into its own
290
501
// BasicBlocks (see function implementation).
@@ -293,10 +504,17 @@ unsigned IROutliner::doOutline(Module &M) {
293
504
OS->CE = new (ExtractorAllocator.Allocate ())
294
505
CodeExtractor (BE, nullptr , false , nullptr , nullptr , nullptr , false ,
295
506
false , " outlined" );
507
+ findAddInputsOutputs (M, *OS);
508
+ if (!OS->IgnoreRegion )
509
+ OutlinedRegions.push_back (OS);
510
+ else
511
+ OS->reattachCandidate ();
296
512
}
297
513
298
- // Create functions out of all the sections, and mark them as outlined
299
- std::vector<OutlinableRegion *> OutlinedRegions;
514
+ CurrentGroup.Regions = std::move (OutlinedRegions);
515
+
516
+ // Create functions out of all the sections, and mark them as outlined.
517
+ OutlinedRegions.clear ();
300
518
for (OutlinableRegion *OS : CurrentGroup.Regions ) {
301
519
OutlinedFunctionNum++;
302
520
bool FunctionOutlined = extractSection (*OS);
0 commit comments