mirror of
https://github.com/intel/intel-graphics-compiler.git
synced 2025-11-04 08:21:06 +08:00
Remove the old coalescing code as it is no longer
needed. More will be deleted in the next few submits. Change-Id: I3165519e13d3d8eda6c2cdbaa0d6f81930bccda7
This commit is contained in:
@ -856,130 +856,9 @@ void VariableReuseAnalysis::visitCallInst(CallInst& I)
|
||||
}
|
||||
}
|
||||
|
||||
void VariableReuseAnalysis::visitCastInst(CastInst& I)
|
||||
{
|
||||
if (IGC_GET_FLAG_VALUE(EnableVATemp) < 1 ||
|
||||
IGC_GET_FLAG_VALUE(EnableDeSSAAlias) > 1)
|
||||
return;
|
||||
|
||||
if (!canBeAlias(&I)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set alias of dst to CastInst's src
|
||||
// As CastInst is noop, its definition is dropped and
|
||||
// only its uses are merged to src's liveness info.
|
||||
Value* D = &I;
|
||||
Value* S = I.getOperand(0);
|
||||
|
||||
SSubVecDesc SV;
|
||||
SV.BaseVector = S;
|
||||
SV.StartElementOffset = 0;
|
||||
if (addAlias(D, SV)) {
|
||||
m_HasBecomeNoopInsts[&I] = 1;
|
||||
}
|
||||
else {
|
||||
// If D is aliased to another value already, it cannot
|
||||
// alias to S again. But we can check if S can be aliased
|
||||
// to D.
|
||||
SV.BaseVector = D;
|
||||
if (addAlias(S, SV)) {
|
||||
m_HasBecomeNoopInsts[&I] = 1;
|
||||
}
|
||||
}
|
||||
// This is probably not needed!
|
||||
// Extend S's liveness to contain D's
|
||||
// m_LV->mergeUseFrom(S, D);
|
||||
}
|
||||
|
||||
// to be deleted
|
||||
void VariableReuseAnalysis::visitInsertElementInst(InsertElementInst& I)
|
||||
{
|
||||
if (IGC_GET_FLAG_VALUE(VATemp) == 0) {
|
||||
// old code
|
||||
visitInsertElementInst_toBeDeleted(I);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void VariableReuseAnalysis::visitInsertElementInst_toBeDeleted(InsertElementInst& I)
|
||||
{
|
||||
if (IGC_GET_FLAG_VALUE(EnableVATemp) < 2)
|
||||
return;
|
||||
|
||||
// Two cases for sub-vector aliasing:
|
||||
// 1. extractFrom: sub-vector is created from a base vector.
|
||||
// For example:
|
||||
// given base: int8 b; a sub-vector s (int4) can be:
|
||||
// s = (int4)(b.s4, b.s5, b.s6, b.s7) // extract and insert in llvm
|
||||
// In this case, 's' becomes a part of 'b'.
|
||||
// 2. insertTo: sub-vector is used to create a base vector.
|
||||
// For example:
|
||||
// given sub-vector int4 s0, s1; int8 vector b is created like:
|
||||
// b = (int8) (s0, s1) // extract and insert
|
||||
// In this case, both s0 and s1 ecome part of b.
|
||||
|
||||
// Start insertElement pattern from the first InsertElement, ie, one with UndefValue.
|
||||
if (!isa<UndefValue>(I.getOperand(0)))
|
||||
return;
|
||||
|
||||
VectorType* VTy = cast<VectorType>(I.getType());
|
||||
int nelts = (int)VTy->getNumElements();
|
||||
|
||||
// Sanity
|
||||
if (nelts < 2)
|
||||
return;
|
||||
|
||||
VecEltTy AllElts(nelts);
|
||||
ValueVectorTy AllIEIs;
|
||||
if (!checkAndGetAllInsertElements(&I, AllIEIs, AllElts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(AllIEIs.size() == nelts && "ICE: wrong the number of IEIs!");
|
||||
|
||||
InsertElementInst* LastIEI = cast<InsertElementInst>(AllIEIs.back());
|
||||
SSubVecDesc SV;
|
||||
SmallVector<SSubVecDesc, 4> SVs;
|
||||
if (IsExtractFrom(AllElts, &I, LastIEI, SV))
|
||||
{
|
||||
if (addAlias(LastIEI, SV))
|
||||
{
|
||||
for (int i = 0, sz = (int)AllIEIs.size(); i < sz; ++i)
|
||||
{
|
||||
Instruction* Inst = cast<Instruction>(AllIEIs[i]);
|
||||
m_HasBecomeNoopInsts[Inst] = 1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SVs.clear();
|
||||
if (IsInsertTo(AllElts, &I, LastIEI, SVs))
|
||||
{
|
||||
for (int i = 0, sz = (int)SVs.size(); i < sz; ++i)
|
||||
{
|
||||
SSubVecDesc& subvec = SVs[i];
|
||||
Value* aliaser = subvec.BaseVector;
|
||||
subvec.BaseVector = LastIEI;
|
||||
if (addAlias(aliaser, subvec)) {
|
||||
VectorType* Ty = dyn_cast<VectorType>(aliaser->getType());
|
||||
int sz = Ty ? (int)Ty->getNumElements() : 1;
|
||||
int startIx = (int)subvec.StartElementOffset;
|
||||
for (int i = startIx, e = startIx + sz; i < e; ++i) {
|
||||
Instruction* Inst = cast<Instruction>(AllIEIs[i]);
|
||||
m_HasBecomeNoopInsts[Inst] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void VariableReuseAnalysis::visitExtractElementInst(ExtractElementInst& I)
|
||||
{
|
||||
if (IGC_GET_FLAG_VALUE(VATemp) == 0) {
|
||||
visitExtractElementInst_toBeDeleted(I);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1050,345 +929,6 @@ void VariableReuseAnalysis::visitExtractElementInst(ExtractElementInst& I)
|
||||
m_HasBecomeNoopInsts[EEI] = 1;
|
||||
}
|
||||
|
||||
void VariableReuseAnalysis::visitExtractElementInst_toBeDeleted(ExtractElementInst& I)
|
||||
{
|
||||
// Only handles ExtractElements whose indexes are all known constants.
|
||||
if (IGC_GET_FLAG_VALUE(EnableVATemp) < 2)
|
||||
return;
|
||||
|
||||
if (m_HasBecomeNoopInsts.count(&I))
|
||||
return;
|
||||
|
||||
// Process all Extract elements of the vector operand.
|
||||
// Do it when the function sees "e0 = EEI V, 0"
|
||||
ConstantInt* Idx = dyn_cast<ConstantInt>(I.getIndexOperand());
|
||||
if (!Idx || Idx->getZExtValue() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Value* Vec = I.getVectorOperand();
|
||||
if (isAliasedValue(Vec))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VectorType* VTy = cast<VectorType>(Vec->getType());
|
||||
int nelts = (int)VTy->getNumElements();
|
||||
SmallVector<ExtractElementInst*, 8> allEEs(nelts, nullptr);
|
||||
allEEs[0] = &I;
|
||||
for (auto user : Vec->users())
|
||||
{
|
||||
ExtractElementInst* EEI = dyn_cast<ExtractElementInst>(user);
|
||||
if (!EEI || EEI == &I)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ConstantInt* Index = dyn_cast<ConstantInt>(EEI->getIndexOperand());
|
||||
if (!Index)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int ix = (int)Index->getZExtValue();
|
||||
if (ix < nelts && allEEs[ix] == nullptr)
|
||||
{
|
||||
allEEs[ix] = EEI;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < nelts; ++i)
|
||||
{
|
||||
ExtractElementInst* EEI = allEEs[i];
|
||||
if (!EEI || isAliasedValue(EEI) ||
|
||||
(m_WIA && m_WIA->whichDepend(EEI) != m_WIA->whichDepend(Vec)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aliasHasInterference(EEI, Vec)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SSubVecDesc SV;
|
||||
SV.BaseVector = Vec;
|
||||
SV.StartElementOffset = i;
|
||||
if (addAlias(EEI, SV)) {
|
||||
m_HasBecomeNoopInsts[EEI] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VariableReuseAnalysis::isLocalValue(Value* V)
|
||||
{
|
||||
Instruction* I = dyn_cast<Instruction>(V);
|
||||
if (!I)
|
||||
return false;
|
||||
BasicBlock* BB = I->getParent();
|
||||
return !m_LV->isLiveIn(I, *BB) && !m_LV->isLiveOut(I, *BB);
|
||||
}
|
||||
|
||||
// Return true if live ranges of aliaser and aliasee overlap. The
|
||||
// difference between this one and hasInterference() is that both aliaser
|
||||
// and aliasee in this function are excluded from congruent class
|
||||
// as they are with the identical value (that is why they are aliased).
|
||||
bool VariableReuseAnalysis::aliasHasInterference(Value* Aliaser, Value* Aliasee)
|
||||
{
|
||||
// As two aliased variables have the identical value, their interference
|
||||
// does not prevent merging them into a single variable (overlapping or not,
|
||||
// they still have the same value).
|
||||
if (!m_DeSSA) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IGC_GET_FLAG_VALUE(EnableVATemp) < 3)
|
||||
{
|
||||
// should have this check ?
|
||||
if (getCongruentClassSize(Aliaser) != 1 ||
|
||||
getCongruentClassSize(Aliasee) != 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// THis is for EnableVATemp =3
|
||||
// [todo] find a better way to handle alias with values whose
|
||||
// congruent class has more than one values.
|
||||
SmallVector<Value*, 8> Aliasercc; // Aliaser's congruent class
|
||||
SmallVector<Value*, 8> Aliaseecc; // Aliasee's congruent class
|
||||
m_DeSSA->getAllValuesInCongruentClass(Aliaser, Aliasercc);
|
||||
m_DeSSA->getAllValuesInCongruentClass(Aliasee, Aliaseecc);
|
||||
|
||||
// Check every pair of values in two congruent classes
|
||||
// and exclude Aliaser and Aliasee.
|
||||
Value* AliaserInsEltRoot = m_DeSSA->getInsEltRoot(Aliaser);
|
||||
Value* AliaseeInsEltRoot = m_DeSSA->getInsEltRoot(Aliasee);
|
||||
for (int i = 0, sz0 = (int)Aliasercc.size(); i < sz0; ++i)
|
||||
{
|
||||
Value* val0 = Aliasercc[i];
|
||||
for (int j = 0, sz1 = (int)Aliaseecc.size(); j < sz1; ++j)
|
||||
{
|
||||
Value* val1 = Aliaseecc[j];
|
||||
if (val0 == AliaserInsEltRoot && val1 == AliaseeInsEltRoot)
|
||||
continue;
|
||||
|
||||
if (m_LV->hasInterference(val0, val1))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if V0 and V1's live ranges overlap, return false otherwise.
|
||||
bool VariableReuseAnalysis::hasInterference(Value* V0, Value* V1)
|
||||
{
|
||||
// Key assumption about Congruent class (dessa)/LVInfo(LiveVars):
|
||||
// 1. Single-definition liveness
|
||||
// LVInfo has liveness info for each llvm value, which has a single
|
||||
// definition throughout its live ranges. This is what LLVM's value means.
|
||||
// 2. Multiple-definition congruent class
|
||||
// If two values are combined, they should be in the same congruent class,
|
||||
// not by extending liveness to reflect both.
|
||||
//
|
||||
// For example:
|
||||
// 1: v0 = 10
|
||||
// 2: = v0 (last use)
|
||||
// 3: v1 = 20
|
||||
// 4: = v1 (last use)
|
||||
// Assume v0 and v1 are combined, they will be put in the same congruent class.
|
||||
// We will not extend v0's liveness to "4" (same for v1).
|
||||
//
|
||||
// Another example:
|
||||
// 1: v0 = 10
|
||||
// 2: = v0 (last use)
|
||||
// 3: v1 = bitcast v0
|
||||
// 4: = v1 (last use)
|
||||
// then we can just extend v0's liveness to "4", and v1 to be alias to v0.
|
||||
//
|
||||
SmallVector<Value*, 8> V0cc; // V0's congruent class
|
||||
SmallVector<Value*, 8> V1cc; // V1's congruent class
|
||||
if (m_DeSSA) {
|
||||
m_DeSSA->getAllValuesInCongruentClass(V0, V0cc);
|
||||
m_DeSSA->getAllValuesInCongruentClass(V1, V1cc);
|
||||
}
|
||||
else {
|
||||
V0cc.push_back(V0);
|
||||
V1cc.push_back(V1);
|
||||
}
|
||||
|
||||
// Check every pair of values in two congruent classes
|
||||
for (int i = 0, sz0 = (int)V0cc.size(); i < sz0; ++i)
|
||||
{
|
||||
Value* val0 = V0cc[i];
|
||||
for (int j = 0, sz1 = (int)V1cc.size(); j < sz1; ++j)
|
||||
{
|
||||
Value* val1 = V1cc[j];
|
||||
if (m_LV->hasInterference(val0, val1))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if src and dst of CastInst can be an alias to each other. It is used
|
||||
// for checking alias-possible instructions such as bitcast/inttoptr/ptrtoint.
|
||||
//
|
||||
// This is trivial for LLVM IR, as LLVM IR is SSA. But after DeSSA,
|
||||
// need to check other values in their congruent classes.
|
||||
//
|
||||
bool VariableReuseAnalysis::canBeAlias(CastInst* I)
|
||||
{
|
||||
if (hasBeenPayloadCoalesced(I)) {
|
||||
return false;
|
||||
}
|
||||
if (!isNoOpInst(I, m_pCtx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set alias of dst to CastInst's src
|
||||
// As CastInst is noop, its definition is dropped and
|
||||
// only its uses are merged to src's liveness info.
|
||||
Value* D = I;
|
||||
Value* S = I->getOperand(0);
|
||||
if (isa<Constant>(S)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasBeenPayloadCoalesced(S)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_DeSSA) {
|
||||
// No congruent class, so it can be alias!
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getCongruentClassSize(D) != 1 ||
|
||||
getCongruentClassSize(S) != 1 ||
|
||||
(m_WIA && m_WIA->whichDepend(D) != m_WIA->whichDepend(S))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the vector value of InsertElement is
|
||||
// a sub-vector of another one, return true if so.
|
||||
bool VariableReuseAnalysis::IsExtractFrom(
|
||||
VecEltTy& AllElts, InsertElementInst* FirstIEI,
|
||||
InsertElementInst* LastIEI, SSubVecDesc& SV)
|
||||
{
|
||||
int nelts = (int)AllElts.size();
|
||||
Value* BaseVec = AllElts[0].Vec;
|
||||
int BaseStartIx = AllElts[0].EltIx;
|
||||
VectorType* BVTy = dyn_cast<VectorType>(BaseVec->getType());
|
||||
if (BVTy == nullptr) {
|
||||
// Base is not a vector, so IEI cannot be
|
||||
// a subvector of another vector!
|
||||
return false;
|
||||
}
|
||||
int base_nelts = (int)BVTy->getNumElements();
|
||||
|
||||
// If Base's size is smaller than IEI's, IEI cannot be sub-vector
|
||||
if (base_nelts < nelts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 1; i < nelts; ++i)
|
||||
{
|
||||
if (AllElts[i].Vec != BaseVec ||
|
||||
AllElts[i].EltIx != (BaseStartIx + i))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't do it if any of them is payload-coalesced
|
||||
if (hasBeenPayloadCoalesced(LastIEI) ||
|
||||
hasBeenPayloadCoalesced(BaseVec) ||
|
||||
(m_WIA && m_WIA->whichDepend(LastIEI) != m_WIA->whichDepend(BaseVec)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aliasHasInterference(LastIEI, BaseVec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SV.StartElementOffset = BaseStartIx;
|
||||
SV.BaseVector = BaseVec;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VariableReuseAnalysis::IsInsertTo(
|
||||
VecEltTy& AllElts, InsertElementInst* FirstIEI,
|
||||
InsertElementInst* LastIEI, SmallVector<SSubVecDesc, 4> & SVs)
|
||||
{
|
||||
int nelts = (int)AllElts.size();
|
||||
Value* SubVec = AllElts[0].Vec;
|
||||
int SubStartIx = 0;
|
||||
|
||||
for (int i = 0; i < nelts; ++i)
|
||||
{
|
||||
// 1. AllElts[i].Vec must be SubVec.
|
||||
// 2. Check the next SubVec, if it change, the current
|
||||
// element is the last one of the crrent SubVec;
|
||||
// and SSubVecDesc will be created if the SubVec meets
|
||||
// the condition.
|
||||
if ((i - SubStartIx) != AllElts[i].EltIx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Value* NextSub = (i < (nelts - 1)) ? AllElts[i + 1].Vec : nullptr;
|
||||
if (SubVec != NextSub)
|
||||
{
|
||||
// NextSub should be the new sub vector. Make sure it is not in SVs
|
||||
// Note this works for speical case in which NextSub = nullptr.
|
||||
for (int j = 0, sz = (int)SVs.size(); j < sz; ++j) {
|
||||
if (SVs[j].BaseVector == NextSub) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// End of the SubVec.
|
||||
VectorType* BVTy = dyn_cast<VectorType>(SubVec->getType());
|
||||
int sub_nelts = BVTy ? (int)BVTy->getNumElements() : 1;
|
||||
// If Sub's size is not smaller than IEI's, or not all sub's
|
||||
// elements are used, skip.
|
||||
if (sub_nelts >= nelts || (i - SubStartIx) != (sub_nelts - 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SSubVecDesc sv;
|
||||
sv.BaseVector = SubVec; // note that this is sub, not base!
|
||||
sv.StartElementOffset = SubStartIx;
|
||||
SVs.push_back(sv);
|
||||
|
||||
SubVec = NextSub;
|
||||
SubStartIx = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If IEI or any of its sub vector has been payload-coalesced, skip.
|
||||
if (hasBeenPayloadCoalesced(LastIEI)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0, sz = (int)SVs.size(); i < sz; ++i)
|
||||
{
|
||||
Value* SubVec = SVs[i].BaseVector;
|
||||
if (hasBeenPayloadCoalesced(SubVec) ||
|
||||
(m_WIA && m_WIA->whichDepend(LastIEI) != m_WIA->whichDepend(SubVec))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0, sz = (int)SVs.size(); i < sz; ++i)
|
||||
{
|
||||
Value* SubVec = SVs[i].BaseVector;
|
||||
if (aliasHasInterference(SubVec, LastIEI)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VariableReuseAnalysis::printAlias(raw_ostream& OS, const Function* F) const
|
||||
{
|
||||
// Assign each inst/arg a unique integer so that the output
|
||||
|
||||
Reference in New Issue
Block a user