Skip to content

Commit dedb944

Browse files
author
git apple-llvm automerger
committed
Merge commit '6ada9e516f49' from llvm.org/master into apple/main
2 parents 945f8b0 + 6ada9e5 commit dedb944

File tree

3 files changed

+622
-51
lines changed

3 files changed

+622
-51
lines changed

llvm/include/llvm/Analysis/IRSimilarityIdentifier.h

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
// or comparison predicate. These are used to create a hash to map instructions
3838
// to integers to be used in similarity matching in sequences of instructions
3939
//
40+
// Terminology:
41+
// An IRSimilarityCandidate is a region of IRInstructionData (wrapped
42+
// Instructions), usually used to denote a region of similarity has been found.
43+
//
4044
//===----------------------------------------------------------------------===//
4145

4246
#ifndef LLVM_ANALYSIS_IRSIMILARITYIDENTIFIER_H
@@ -386,6 +390,137 @@ struct IRInstructionMapper {
386390
InstructionClassification InstClassifier;
387391
};
388392

393+
/// This is a class that wraps a range of IRInstructionData from one point to
394+
/// another in the vector of IRInstructionData, which is a region of the
395+
/// program. It is also responsible for defining the structure within this
396+
/// region of instructions.
397+
///
398+
/// The structure of a region is defined through a value numbering system
399+
/// assigned to each unique value in a region at the creation of the
400+
/// IRSimilarityCandidate.
401+
///
402+
/// For example, for each Instruction we add a mapping for each new
403+
/// value seen in that Instruction.
404+
/// IR: Mapping Added:
405+
/// %add1 = add i32 %a, c1 %add1 -> 3, %a -> 1, c1 -> 2
406+
/// %add2 = add i32 %a, %1 %add2 -> 4
407+
/// %add3 = add i32 c2, c1 %add3 -> 6, c2 -> 5
408+
///
409+
/// We can compare IRSimilarityCandidates against one another.
410+
/// The \ref isSimilar function compares each IRInstructionData against one
411+
/// another and if we have the same sequences of IRInstructionData that would
412+
/// create the same hash, we have similar IRSimilarityCandidates.
413+
class IRSimilarityCandidate {
414+
private:
415+
/// The start index of this IRSimilarityCandidate in the instruction list.
416+
unsigned StartIdx = 0;
417+
418+
/// The number of instructions in this IRSimilarityCandidate.
419+
unsigned Len = 0;
420+
421+
/// The first instruction in this IRSimilarityCandidate.
422+
IRInstructionData *FirstInst = nullptr;
423+
424+
/// The last instruction in this IRSimilarityCandidate.
425+
IRInstructionData *LastInst = nullptr;
426+
427+
/// Global Value Numbering structures
428+
/// @{
429+
/// Stores the mapping of the value to the number assigned to it in the
430+
/// IRSimilarityCandidate.
431+
DenseMap<Value *, unsigned> ValueToNumber;
432+
/// Stores the mapping of the number to the value assigned this number.
433+
DenseMap<unsigned, Value *> NumberToValue;
434+
/// @}
435+
436+
public:
437+
/// \param StartIdx - The starting location of the region.
438+
/// \param StartIdx - The length of the region.
439+
/// \param FirstInstIt - The starting IRInstructionData of the region.
440+
/// \param LastInstIt - The ending IRInstructionData of the region.
441+
IRSimilarityCandidate(unsigned StartIdx, unsigned Len,
442+
IRInstructionData *FirstInstIt,
443+
IRInstructionData *LastInstIt);
444+
445+
/// \param A - The first IRInstructionCandidate to compare.
446+
/// \param B - The second IRInstructionCandidate to compare.
447+
/// \returns True when every IRInstructionData in \p A is similar to every
448+
/// IRInstructionData in \p B.
449+
static bool isSimilar(const IRSimilarityCandidate &A,
450+
const IRSimilarityCandidate &B);
451+
/// Compare the start and end indices of the two IRSimilarityCandidates for
452+
/// whether they overlap. If the start instruction of one
453+
/// IRSimilarityCandidate is less than the end instruction of the other, and
454+
/// the start instruction of one is greater than the start instruction of the
455+
/// other, they overlap.
456+
///
457+
/// \returns true if the IRSimilarityCandidates do not have overlapping
458+
/// instructions.
459+
static bool overlap(const IRSimilarityCandidate &A,
460+
const IRSimilarityCandidate &B);
461+
462+
/// \returns the number of instructions in this Candidate.
463+
unsigned getLength() const { return Len; }
464+
465+
/// \returns the start index of this IRSimilarityCandidate.
466+
unsigned getStartIdx() const { return StartIdx; }
467+
468+
/// \returns the end index of this IRSimilarityCandidate.
469+
unsigned getEndIdx() const { return StartIdx + Len - 1; }
470+
471+
/// \returns The first IRInstructionData.
472+
IRInstructionData *front() const { return FirstInst; }
473+
/// \returns The last IRInstructionData.
474+
IRInstructionData *back() const { return LastInst; }
475+
476+
/// \returns The first Instruction.
477+
Instruction *frontInstruction() { return FirstInst->Inst; }
478+
/// \returns The last Instruction
479+
Instruction *backInstruction() { return LastInst->Inst; }
480+
481+
/// \returns The BasicBlock the IRSimilarityCandidate starts in.
482+
BasicBlock *getStartBB() { return FirstInst->Inst->getParent(); }
483+
/// \returns The BasicBlock the IRSimilarityCandidate ends in.
484+
BasicBlock *getEndBB() { return LastInst->Inst->getParent(); }
485+
486+
/// \returns The Function that the IRSimilarityCandidate is located in.
487+
Function *getFunction() { return getStartBB()->getParent(); }
488+
489+
/// Finds the positive number associated with \p V if it has been mapped.
490+
/// \param [in] V - the Value to find.
491+
/// \returns The positive number corresponding to the value.
492+
/// \returns None if not present.
493+
Optional<unsigned> getGVN(Value *V) {
494+
assert(V != nullptr && "Value is a nullptr?");
495+
DenseMap<Value *, unsigned>::iterator VNIt = ValueToNumber.find(V);
496+
if (VNIt == ValueToNumber.end())
497+
return None;
498+
return VNIt->second;
499+
}
500+
501+
/// Finds the Value associate with \p Num if it exists.
502+
/// \param [in] Num - the number to find.
503+
/// \returns The Value associated with the number.
504+
/// \returns None if not present.
505+
Optional<Value *> fromGVN(unsigned Num) {
506+
DenseMap<unsigned, Value *>::iterator VNIt = NumberToValue.find(Num);
507+
if (VNIt == NumberToValue.end())
508+
return None;
509+
assert(VNIt->second != nullptr && "Found value is a nullptr!");
510+
return VNIt->second;
511+
}
512+
513+
/// \param RHS -The IRSimilarityCandidate to compare against
514+
/// \returns true if the IRSimilarityCandidate is occurs after the
515+
/// IRSimilarityCandidate in the program.
516+
bool operator<(const IRSimilarityCandidate &RHS) const {
517+
return getStartIdx() > RHS.getStartIdx();
518+
}
519+
520+
using iterator = IRInstructionDataList::iterator;
521+
iterator begin() const { return iterator(front()); }
522+
iterator end() const { return std::next(iterator(back())); }
523+
};
389524
} // end namespace IRSimilarity
390525
} // end namespace llvm
391526

llvm/lib/Analysis/IRSimilarityIdentifier.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,91 @@ unsigned IRInstructionMapper::mapToIllegalUnsigned(
163163

164164
return INumber;
165165
}
166+
167+
IRSimilarityCandidate::IRSimilarityCandidate(unsigned StartIdx, unsigned Len,
168+
IRInstructionData *FirstInstIt,
169+
IRInstructionData *LastInstIt)
170+
: StartIdx(StartIdx), Len(Len) {
171+
172+
assert(FirstInstIt != nullptr && "Instruction is nullptr!");
173+
assert(LastInstIt != nullptr && "Instruction is nullptr!");
174+
assert(StartIdx + Len > StartIdx &&
175+
"Overflow for IRSimilarityCandidate range?");
176+
assert(Len - 1 ==
177+
std::distance(iterator(FirstInstIt), iterator(LastInstIt)) &&
178+
"Length of the first and last IRInstructionData do not match the "
179+
"given length");
180+
181+
// We iterate over the given instructions, and map each unique value
182+
// to a unique number in the IRSimilarityCandidate ValueToNumber and
183+
// NumberToValue maps. A constant get its own value globally, the individual
184+
// uses of the constants are not considered to be unique.
185+
//
186+
// IR: Mapping Added:
187+
// %add1 = add i32 %a, c1 %add1 -> 3, %a -> 1, c1 -> 2
188+
// %add2 = add i32 %a, %1 %add2 -> 4
189+
// %add3 = add i32 c2, c1 %add3 -> 6, c2 -> 5
190+
//
191+
// when replace with global values, starting from 1, would be
192+
//
193+
// 3 = add i32 1, 2
194+
// 4 = add i32 1, 3
195+
// 6 = add i32 5, 2
196+
unsigned LocalValNumber = 1;
197+
IRInstructionDataList::iterator ID = iterator(*FirstInstIt);
198+
for (unsigned Loc = StartIdx; Loc < StartIdx + Len; Loc++, ID++) {
199+
// Map the operand values to an unsigned integer if it does not already
200+
// have an unsigned integer assigned to it.
201+
for (Value *Arg : ID->OperVals)
202+
if (ValueToNumber.find(Arg) == ValueToNumber.end()) {
203+
ValueToNumber.try_emplace(Arg, LocalValNumber);
204+
NumberToValue.try_emplace(LocalValNumber, Arg);
205+
LocalValNumber++;
206+
}
207+
208+
// Mapping the instructions to an unsigned integer if it is not already
209+
// exist in the mapping.
210+
if (ValueToNumber.find(ID->Inst) == ValueToNumber.end()) {
211+
ValueToNumber.try_emplace(ID->Inst, LocalValNumber);
212+
NumberToValue.try_emplace(LocalValNumber, ID->Inst);
213+
LocalValNumber++;
214+
}
215+
}
216+
217+
// Setting the first and last instruction data pointers for the candidate. If
218+
// we got through the entire for loop without hitting an assert, we know
219+
// that both of these instructions are not nullptrs.
220+
FirstInst = FirstInstIt;
221+
LastInst = LastInstIt;
222+
}
223+
224+
bool IRSimilarityCandidate::isSimilar(const IRSimilarityCandidate &A,
225+
const IRSimilarityCandidate &B) {
226+
if (A.getLength() != B.getLength())
227+
return false;
228+
229+
auto InstrDataForBoth =
230+
zip(make_range(A.begin(), A.end()), make_range(B.begin(), B.end()));
231+
232+
return all_of(InstrDataForBoth,
233+
[](std::tuple<IRInstructionData &, IRInstructionData &> R) {
234+
IRInstructionData &A = std::get<0>(R);
235+
IRInstructionData &B = std::get<1>(R);
236+
if (!A.Legal || !B.Legal)
237+
return false;
238+
return isClose(A, B);
239+
});
240+
}
241+
242+
bool IRSimilarityCandidate::overlap(const IRSimilarityCandidate &A,
243+
const IRSimilarityCandidate &B) {
244+
auto DoesOverlap = [](const IRSimilarityCandidate &X,
245+
const IRSimilarityCandidate &Y) {
246+
// Check:
247+
// XXXXXX X starts before Y ends
248+
// YYYYYYY Y starts after X starts
249+
return X.StartIdx <= Y.getEndIdx() && Y.StartIdx >= X.StartIdx;
250+
};
251+
252+
return DoesOverlap(A, B) || DoesOverlap(B, A);
253+
}

0 commit comments

Comments
 (0)