LLVM 24.0.0git
SLPCompatibilityAnalysis.h
Go to the documentation of this file.
1//===- SLPCompatibilityAnalysis.h - SLP same-opcode helpers ----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Internal header used by SLPVectorizer.cpp. It declares the same-opcode
10// compatibility primitives that decide whether a group of values can be
11// treated as sharing the same (or an interchangeable/alternate) opcode. These
12// do not depend on BoUpSLP or any other SLP-private type.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPCOMPATIBILITYANALYSIS_H
17#define LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPCOMPATIBILITYANALYSIS_H
18
19#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/STLExtras.h"
24#include "llvm/IR/Instruction.h"
26
27#include <cstdint>
28#include <utility>
29
30namespace llvm {
31class APInt;
32class Constant;
33class ConstantInt;
35class Value;
36} // namespace llvm
37
38namespace llvm::slpvectorizer {
39
40/// \returns true if \p Opcode is allowed as part of the main/alternate
41/// instruction for SLP vectorization.
42///
43/// Example of unsupported opcode is SDIV that can potentially cause UB if the
44/// "shuffled out" lane would result in division by zero.
45bool isValidForAlternation(unsigned Opcode);
46
47/// Helper class that determines VL can use the same opcode.
48/// Alternate instruction is supported. In addition, it supports interchangeable
49/// instruction. An interchangeable instruction is an instruction that can be
50/// converted to another instruction with same semantics. For example, x << 1 is
51/// equal to x * 2. x * 1 is equal to x | 0.
53 using MaskType = std::uint_fast32_t;
54 /// Sort SupportedOp because it is used by binary_search.
55 constexpr static unsigned SupportedOp[] = {
56 Instruction::Add, Instruction::FAdd, Instruction::Sub, Instruction::FSub,
57 Instruction::Mul, Instruction::Shl, Instruction::AShr, Instruction::And,
58 Instruction::Or, Instruction::Xor};
59 static_assert(llvm::is_sorted_constexpr(SupportedOp) &&
60 "SupportedOp is not sorted.");
61 enum : MaskType {
62 ShlBIT = 1,
63 AShrBIT = 1 << 1,
64 MulBIT = 1 << 2,
65 AddBIT = 1 << 3,
66 SubBIT = 1 << 4,
67 AndBIT = 1 << 5,
68 OrBIT = 1 << 6,
69 XorBIT = 1 << 7,
70 FAddBIT = 1 << 8,
71 FSubBIT = 1 << 9,
72 MainOpBIT = 1 << 10,
74 };
75 /// Return a non-nullptr if either operand of I is a ConstantInt (for the
76 /// integer opcodes) or a ConstantFP (for FAdd/FSub).
77 /// The second return value represents the operand position. We check the
78 /// right-hand side first (1). If the right hand side is not a constant and
79 /// the instruction is neither Sub, FSub, Shl, nor AShr, we then check the
80 /// left hand side (0).
81 static std::pair<Constant *, unsigned>
82 isBinOpWithConstant(const Instruction *I);
83 struct InterchangeableInfo {
84 const Instruction *I = nullptr;
85 /// The bit it sets represents whether MainOp can be converted to.
86 MaskType Mask = MainOpBIT | XorBIT | OrBIT | AndBIT | SubBIT | AddBIT |
87 MulBIT | AShrBIT | ShlBIT | FSubBIT | FAddBIT;
88 /// We cannot create an interchangeable instruction that does not exist in
89 /// VL. For example, VL [x + 0, y * 1] can be converted to [x << 0, y << 0],
90 /// but << does not exist in VL. In the end, we convert VL to [x * 1, y *
91 /// 1]. SeenBefore is used to know what operations have been seen before.
92 MaskType SeenBefore = 0;
93 InterchangeableInfo(const Instruction *I) : I(I) {}
94 /// Return false allows BinOpSameOpcodeHelper to find an alternate
95 /// instruction. Directly setting the mask will destroy the mask state,
96 /// preventing us from determining which instruction it should convert to.
97 bool trySet(MaskType OpcodeInMaskForm, MaskType InterchangeableMask);
98 bool equal(unsigned Opcode) {
99 return Opcode == I->getOpcode() && trySet(MainOpBIT, MainOpBIT);
100 }
101 unsigned getOpcode() const;
102 bool hasDefinedOpcode() const { return (Mask & SeenBefore) > 0; }
103 /// Return true if the instruction can be converted to \p Opcode.
104 bool hasCandidateOpcode(unsigned Opcode) const;
106 };
107 InterchangeableInfo MainOp;
108 InterchangeableInfo AltOp;
109 bool isValidForAlternation(const Instruction *I) const;
110 bool initializeAltOp(const Instruction *I);
111
112public:
114 const Instruction *AltOp = nullptr)
115 : MainOp(MainOp), AltOp(AltOp) {}
116 bool add(const Instruction *I);
117 unsigned getMainOpcode() const { return MainOp.getOpcode(); }
118 bool hasDefinedMainOpcode() const { return MainOp.hasDefinedOpcode(); }
119 /// Checks if the list of potential opcodes includes \p Opcode.
120 bool hasCandidateOpcode(unsigned Opcode) const {
121 return MainOp.hasCandidateOpcode(Opcode);
122 }
123 bool hasAltOp() const { return AltOp.I; }
124 unsigned getAltOpcode() const {
125 return hasAltOp() ? AltOp.getOpcode() : getMainOpcode();
126 }
127 bool hasDefinedAltOpcode() const {
128 return !hasAltOp() || AltOp.hasDefinedOpcode();
129 }
131 return MainOp.getOperand(I);
132 }
133};
134
135/// Helper class that determines whether a list of integer comparisons can
136/// share a single predicate. InstCombine canonicalizes single-element and
137/// single-complement range comparisons to eq/ne at the type boundaries
138/// (e.g. x <u 1 becomes x == 0); such lanes are interchangeable with the
139/// rest of the list by adjusting the compared constant. InstCombine also
140/// canonicalizes icmp ne (and X, 1), 0 to trunc X to i1, such lanes are
141/// treated as the original comparison or as icmp eq (and X, 1), 1.
143 using MaskType = std::uint16_t;
144 /// Bit i represents predicate ICMP_EQ + i.
145 static constexpr unsigned NumPreds = CmpInst::ICMP_SLE - CmpInst::ICMP_EQ + 1;
146 static constexpr MaskType AllPreds = (1 << NumPreds) - 1;
147 /// Intersection of the per-lane convertible predicate sets.
148 MaskType Mask = AllPreds;
149 /// Predicates present in the list natively. The shared predicate must be
150 /// one of them: the main op must be an actual instruction with this
151 /// predicate.
152 MaskType SeenBefore = 0;
153
154 static constexpr MaskType getBit(CmpInst::Predicate P) {
155 return static_cast<MaskType>(1) << (P - CmpInst::ICMP_EQ);
156 }
157 /// Returns the mask of the predicates that can express the comparison
158 /// (Pred, X, C) with an adjusted constant C, including Pred itself.
159 static MaskType getFormsMask(CmpInst::Predicate Pred, const APInt &C);
160 /// Returns the constant of the (Pred, X, C') form equivalent to the
161 /// boundary family (IsComplement, K). Pred must be in the family mask.
162 static APInt getFamilyConstant(bool IsComplement, const APInt &K,
163 CmpInst::Predicate Pred);
164 /// Returns the mask of the predicates that can express the comparison
165 /// lane \p I, or 0 if \p I is not a comparison lane.
166 static MaskType getLaneMask(const Instruction *I);
167
168public:
169 /// Intersects the convertible predicate set of the comparison lane \p I
170 /// (an icmp or a trunc to i1) with the running set. Returns false when the
171 /// intersection becomes empty.
172 bool add(const Instruction *I);
173 /// Returns the shared predicate, preferring the predicate of
174 /// \p Preferred when the whole list can use it, or BAD_ICMP_PREDICATE
175 /// when the list cannot share a natively present predicate.
176 CmpInst::Predicate getPredicate(const ICmpInst *Preferred) const;
177 /// Returns the predicate the whole list can share, or BAD_ICMP_PREDICATE
178 /// when it cannot share a natively present predicate.
180 const ICmpInst *Preferred);
181 /// Checks if the comparison lane \p I is the bit test of the single use
182 /// and A, B != 0 or and A, B == 0, or trunc X to i1, which is
183 /// and X, 1 != 0.
184 static bool isBitTest(const Instruction *I);
185 /// Checks if the comparison lane \p I can be expressed with the predicate
186 /// \p Pred by adjusting its constant operand.
187 static bool canConvertTo(const Instruction *I, CmpInst::Predicate Pred);
188 /// Returns the adjusted constant operand expressing the comparison lane
189 /// \p I with the predicate \p Pred, or nullptr if not convertible or if
190 /// \p I is a compare already using \p Pred.
192 CmpInst::Predicate Pred);
193};
194
195/// Checks if \p I is a call to llvm.fma or llvm.fmuladd.
196bool isFMAOrFMulAdd(const Instruction *I);
197
198/// Main data required for vectorization of instructions.
200 /// MainOp and AltOp are primarily determined by getSameOpcode. Currently,
201 /// only BinaryOperator, CastInst, and CmpInst support alternate instructions
202 /// (i.e., AltOp is not equal to MainOp; this can be checked using
203 /// isAltShuffle).
204 /// A rare exception is TrySplitNode, where the InstructionsState is derived
205 /// from getMainAltOpsNoStateVL.
206 /// For those InstructionsState that use alternate instructions, the resulting
207 /// vectorized output ultimately comes from a shufflevector. For example,
208 /// given a vector list (VL):
209 /// VL[0] = add i32 a, e
210 /// VL[1] = sub i32 b, f
211 /// VL[2] = add i32 c, g
212 /// VL[3] = sub i32 d, h
213 /// The vectorized result would be:
214 /// intermediated_0 = add <4 x i32> <a, b, c, d>, <e, f, g, h>
215 /// intermediated_1 = sub <4 x i32> <a, b, c, d>, <e, f, g, h>
216 /// result = shufflevector <4 x i32> intermediated_0,
217 /// <4 x i32> intermediated_1,
218 /// <4 x i32> <i32 0, i32 5, i32 2, i32 7>
219 /// Since shufflevector is used in the final result, when calculating the cost
220 /// (getEntryCost), we must account for the usage of shufflevector in
221 /// GetVectorCost.
222 Instruction *MainOp = nullptr;
223 Instruction *AltOp = nullptr;
224 /// Whether the instruction state represents copyable instructions.
225 bool HasCopyables = false;
226 /// Index of the operand modeling the copyable values: the addend for
227 /// fma/fmuladd (retried with a multiplicand), the first operand otherwise.
228 unsigned CopyableOpIdx = 0;
229 /// Whether copyable single-use fmuls/fadds are modeled as
230 /// fmuladd(a, b, -0.0)/fmuladd(1.0, a, b), absorbing the binop instead of
231 /// computing and gathering its result.
232 bool AbsorbCopyableFMulOrFAdd = false;
233
234public:
236 assert(valid() && "InstructionsState is invalid.");
237 return MainOp;
238 }
239
241 assert(valid() && "InstructionsState is invalid.");
242 return AltOp;
243 }
244
245 /// The main/alternate opcodes for the list of instructions.
246 unsigned getOpcode() const { return getMainOp()->getOpcode(); }
247
248 unsigned getAltOpcode() const { return getAltOp()->getOpcode(); }
249
250 /// Some of the instructions in the list have alternate opcodes.
251 bool isAltShuffle() const { return getMainOp() != getAltOp(); }
252
253 /// Checks if \p I is the same operation as \p Op, distinguishing calls by
254 /// intrinsic ID (all calls share the Call opcode, so e.g. umax != smax).
255 static bool isSameOperation(const Instruction *I, const Instruction *Op);
256
257 /// Checks if the instruction matches either the main or alternate opcode.
258 /// \returns
259 /// - MainOp if \param I matches MainOp's opcode directly or can be converted
260 /// to it
261 /// - AltOp if \param I matches AltOp's opcode directly or can be converted to
262 /// it
263 /// - nullptr if \param I cannot be matched or converted to either opcode
265
266 /// Checks if main/alt instructions are shift operations.
267 bool isShiftOp() const {
268 return getMainOp()->isShift() && getAltOp()->isShift();
269 }
270
271 /// Checks if main/alt instructions are bitwise logic operations.
272 bool isBitwiseLogicOp() const {
274 }
275
276 /// Checks if main/alt instructions are mul/div/rem/fmul/fdiv/frem operations.
277 bool isMulDivLikeOp() const;
278
279 /// Checks if main/alt instructions are add/sub/fadd/fsub operations.
280 bool isAddSubLikeOp() const;
281
282 /// Checks for an add/sub-like operation or an fneg, which models a
283 /// flattened fadd reduction chain link: the link is dropped and its
284 /// operand joins a sign-flipped combine, which may form an fma as well.
285 bool isAddSubOrFNegLikeOp() const;
286
287 /// Checks if main/alt instructions are cmp operations.
288 bool isCmpOp() const {
289 return (getOpcode() == Instruction::ICmp ||
290 getOpcode() == Instruction::FCmp) &&
291 getAltOpcode() == getOpcode();
292 }
293
294 /// Checks if the current state is valid, i.e. has non-null MainOp
295 bool valid() const { return MainOp && AltOp; }
296
297 explicit operator bool() const { return valid(); }
298
301 bool HasCopyables = false)
302 : MainOp(MainOp), AltOp(AltOp), HasCopyables(HasCopyables),
303 CopyableOpIdx(MainOp && isFMAOrFMulAdd(MainOp) ? 2 : 0) {}
304 static InstructionsState invalid() { return {nullptr, nullptr}; }
305
306 /// Checks if the value is a copyable element.
307 bool isCopyableElement(Value *V) const;
308
309 /// Checks if the value \p V is a transformed instruction, compatible either
310 /// with main or alternate ops.
311 bool isExpandedBinOp(Value *V) const;
312
313 /// Checks if the operand at index \p Idx of instruction \p I is an expanded
314 /// operand.
315 bool isExpandedOperand(Instruction *I, unsigned Idx) const;
316
317 /// Checks if the value is non-schedulable.
318 bool isNonSchedulable(Value *V) const;
319
320 /// Checks if the state represents copyable instructions.
322 assert(valid() && "InstructionsState is invalid.");
323 return HasCopyables;
324 }
325
326 /// Returns the index of the operand the copyable value is modeled in.
327 unsigned getCopyableOpIdx() const {
328 assert(valid() && "InstructionsState is invalid.");
329 return CopyableOpIdx;
330 }
331
332 /// Sets the index of the operand the copyable value is modeled in.
333 void setCopyableOpIdx(unsigned Idx) {
334 assert((Idx == 0 || Idx == 2) && "Unexpected copyable operand index.");
335 CopyableOpIdx = Idx;
336 }
337
338 /// Checks if copyable fmuls/fadds are absorbed as fmuladd(a, b, -0.0) or
339 /// fmuladd(1.0, a, b).
341 assert(valid() && "InstructionsState is invalid.");
342 return AbsorbCopyableFMulOrFAdd;
343 }
344
345 /// Sets the absorbed-fmul/fadd modeling for copyable fmuls/fadds.
346 void setAbsorbCopyableFMulOrFAdd(bool Absorb) {
347 AbsorbCopyableFMulOrFAdd = Absorb;
348 }
349};
350
351/// Checks if \p V is a single-use fmul/fadd with operands outside \p VL.
353
354/// Checks if \p V is a copyable single-use fmul/fadd, absorbable as
355/// fmuladd(a, b, -0.0) or fmuladd(1.0, a, b).
356bool isAbsorbableCopyableFMulOrFAdd(const InstructionsState &S, Value *V);
357
358/// Checks if every copyable in \p VL is an absorbable fmul/fadd: the binops
359/// die instead of being computed and gathered. Operand order is normalized
360/// when the operands are built.
362
363/// \returns analysis of the Instructions in \p VL described in
364/// InstructionsState, the Opcode that we suppose the whole list
365/// could be vectorized even if its structure is diverse.
366InstructionsState getSameOpcode(ArrayRef<Value *> VL,
367 const TargetLibraryInfo &TLI);
368
369/// \returns the main or alternate operation from \p S matching \p I, together
370/// with the operands of \p I adjusted to the selected operation.
371std::pair<Instruction *, SmallVector<Value *>>
372convertTo(Instruction *I, const InstructionsState &S);
373
374/// Checks if the specified instruction \p I is an alternate operation for
375/// the given \p MainOp and \p AltOp instructions.
377 Instruction *AltOp, const TargetLibraryInfo &TLI);
378
379/// Peel the per-lane associative chains of an alternate node into operand
380/// columns. Lanes peel in lockstep and only chain links with the lane's own
381/// opcode, so every combine level keeps the root's main/alt opcode pattern
382/// and a subtract lane never becomes an add of a negated leaf. Only the
383/// leading (running) column peels: peeling a subtracted subtract would flip
384/// signs. \p SubLanes records the subtract lanes for the realignment sign
385/// query. Returns the flattened columns, empty when no level peels.
387 const InstructionsState &S, const TargetLibraryInfo &TLI,
389 SmallVectorImpl<Value *> &ReassocScalars, SmallBitVector &SubLanes);
390} // namespace llvm::slpvectorizer
391
392#endif // LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPCOMPATIBILITYANALYSIS_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
#define I(x, y, z)
Definition MD5.cpp:57
#define P(N)
This file contains some templates that are useful if you are working with the STL at all.
This file implements the SmallBitVector class.
This file defines the SmallVector class.
Class for arbitrary precision integers.
Definition APInt.h:78
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
This is the shared class of boolean and integer constants.
Definition Constants.h:87
This is an important base class in LLVM.
Definition Constant.h:44
This instruction compares its operands according to the predicate given to the constructor.
static bool isBitwiseLogicOp(unsigned Opcode)
Determine if the Opcode is and/or/xor.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
bool isShift() const
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Provides information about what library functions are available for the current target.
LLVM Value Representation.
Definition Value.h:75
SmallVector< Value * > getOperand(const Instruction *I) const
bool hasCandidateOpcode(unsigned Opcode) const
Checks if the list of potential opcodes includes Opcode.
BinOpSameOpcodeHelper(const Instruction *MainOp, const Instruction *AltOp=nullptr)
Helper class that determines whether a list of integer comparisons can share a single predicate.
static CmpInst::Predicate getSharedPredicate(ArrayRef< Value * > VL, const ICmpInst *Preferred)
Returns the predicate the whole list can share, or BAD_ICMP_PREDICATE when it cannot share a natively...
static Constant * getAdjustedConstant(const Instruction *I, CmpInst::Predicate Pred)
Returns the adjusted constant operand expressing the comparison lane I with the predicate Pred,...
CmpInst::Predicate getPredicate(const ICmpInst *Preferred) const
Returns the shared predicate, preferring the predicate of Preferred when the whole list can use it,...
static bool isBitTest(const Instruction *I)
Checks if the comparison lane I is the bit test of the single use and A, B != 0 or and A,...
bool add(const Instruction *I)
Intersects the convertible predicate set of the comparison lane I (an icmp or a trunc to i1) with the...
static bool canConvertTo(const Instruction *I, CmpInst::Predicate Pred)
Checks if the comparison lane I can be expressed with the predicate Pred by adjusting its constant op...
Instruction * getMatchingMainOpOrAltOp(Instruction *I) const
Checks if the instruction matches either the main or alternate opcode.
bool areInstructionsWithCopyableElements() const
Checks if the state represents copyable instructions.
void setAbsorbCopyableFMulOrFAdd(bool Absorb)
Sets the absorbed-fmul/fadd modeling for copyable fmuls/fadds.
bool isCmpOp() const
Checks if main/alt instructions are cmp operations.
static bool isSameOperation(const Instruction *I, const Instruction *Op)
Checks if I is the same operation as Op, distinguishing calls by intrinsic ID (all calls share the Ca...
bool valid() const
Checks if the current state is valid, i.e. has non-null MainOp.
bool isExpandedBinOp(Value *V) const
Checks if the value V is a transformed instruction, compatible either with main or alternate ops.
bool isAddSubLikeOp() const
Checks if main/alt instructions are add/sub/fadd/fsub operations.
bool isShiftOp() const
Checks if main/alt instructions are shift operations.
bool isExpandedOperand(Instruction *I, unsigned Idx) const
Checks if the operand at index Idx of instruction I is an expanded operand.
bool isCopyableElement(Value *V) const
Checks if the value is a copyable element.
bool hasAbsorbedCopyableFMulOrFAdd() const
Checks if copyable fmuls/fadds are absorbed as fmuladd(a, b, -0.0) or fmuladd(1.0,...
bool isAltShuffle() const
Some of the instructions in the list have alternate opcodes.
void setCopyableOpIdx(unsigned Idx)
Sets the index of the operand the copyable value is modeled in.
InstructionsState(Instruction *MainOp, Instruction *AltOp, bool HasCopyables=false)
bool isNonSchedulable(Value *V) const
Checks if the value is non-schedulable.
bool isAddSubOrFNegLikeOp() const
Checks for an add/sub-like operation or an fneg, which models a flattened fadd reduction chain link: ...
unsigned getCopyableOpIdx() const
Returns the index of the operand the copyable value is modeled in.
bool isBitwiseLogicOp() const
Checks if main/alt instructions are bitwise logic operations.
bool isMulDivLikeOp() const
Checks if main/alt instructions are mul/div/rem/fmul/fdiv/frem operations.
unsigned getOpcode() const
The main/alternate opcodes for the list of instructions.
A private "module" namespace for types and utilities used by this pass.
SmallVector< SmallVector< Value * > > scanAltAssociativeOperands(const InstructionsState &S, const TargetLibraryInfo &TLI, ArrayRef< Value * > VL, ArrayRef< Value * > Op0, ArrayRef< Value * > Op1, SmallVectorImpl< Value * > &ReassocScalars, SmallBitVector &SubLanes)
Peel the per-lane associative chains of an alternate node into operand columns.
std::pair< Instruction *, SmallVector< Value * > > convertTo(Instruction *I, const InstructionsState &S)
bool isAlternateInstruction(Instruction *I, Instruction *MainOp, Instruction *AltOp, const TargetLibraryInfo &TLI)
Checks if the specified instruction I is an alternate operation for the given MainOp and AltOp instru...
bool isValidForAlternation(unsigned Opcode)
bool hasOnlyAbsorbableCopyableFMulOrFAdds(ArrayRef< Value * > VL)
Checks if every copyable in VL is an absorbable fmul/fadd: the binops die instead of being computed a...
bool isFMAOrFMulAdd(const Instruction *I)
Checks if I is a call to llvm.fma or llvm.fmuladd.
InstructionsState getSameOpcode(ArrayRef< Value * > VL, const TargetLibraryInfo &TLI)
bool isAbsorbableCopyableFMulOrFAdd(const InstructionsState &S, Value *V)
Checks if V is a copyable single-use fmul/fadd, absorbable as fmuladd(a, b, -0.0) or fmuladd(1....
bool isAbsorbableFMulOrFAdd(ArrayRef< Value * > VL, Value *V)
Checks if V is a single-use fmul/fadd with operands outside VL.
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool is_sorted_constexpr(R &&Range, Cmp C=Cmp{})
Check if elements in a range R are sorted with respect to a comparator C.
Definition STLExtras.h:2000
DWARFExpression::Operation Op
bool equal(L &&LRange, R &&RRange)
Wrapper function around std::equal to detect if pair-wise elements between two ranges are the same.
Definition STLExtras.h:2162