Skip to content

Commit f1fe908

Browse files
ppogotovigcbot
authored andcommitted
Extending Memopt analysis.
Allow Memopt to look one instruction further, even if the operand of the current instruction is not constant.
1 parent 95735af commit f1fe908

File tree

2 files changed

+431
-88
lines changed

2 files changed

+431
-88
lines changed

IGC/Compiler/CISACodeGen/MemOpt.cpp

Lines changed: 187 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -412,45 +412,19 @@ namespace {
412412
int64_t Offset;
413413
SmallVector<Term, 8> Terms;
414414

415-
// getConstantOffset - Return the constant offset between two memory
416-
// locations.
417-
bool getConstantOffset(const SymbolicPointer& Other, int64_t& Off) {
418-
if (!BasePtr || !Other.BasePtr)
419-
return true;
420-
421-
if (BasePtr != Other.BasePtr &&
422-
(!isa<ConstantPointerNull>(BasePtr) ||
423-
!isa<ConstantPointerNull>(Other.BasePtr)))
424-
return true;
425-
426-
if (Terms.size() != Other.Terms.size())
427-
return true;
428-
429-
// Check each term has occurrence in Other. Since, they have the same
430-
// number of terms, it's safe to say they are equal if all terms are
431-
// found in Other.
432-
// TODO: Replace this check with a non-quadratic one.
433-
for (unsigned i = 0, e = Terms.size(); i != e; ++i) {
434-
bool Found = false;
435-
for (unsigned j = 0, f = Other.Terms.size(); !Found && j != f; ++j) {
436-
if (Terms[i] == Other.Terms[j])
437-
Found = true;
438-
}
439-
if (!Found)
440-
return true;
441-
}
442-
443-
Off = Offset - Other.Offset;
444-
return false;
445-
}
446-
415+
bool getConstantOffset(SymbolicPointer& Other, int64_t& Off);
447416
static Value* getLinearExpression(Value* Val, APInt& Scale, APInt& Offset,
448417
ExtensionKind& Extension, unsigned Depth,
449418
const DataLayout* DL);
450419
static bool decomposePointer(const Value* Ptr, SymbolicPointer& SymPtr,
451420
CodeGenContext* DL);
452421

453422
static const unsigned MaxLookupSearchDepth = 6;
423+
424+
private:
425+
void saveTerm(Value* Src, int64_t IndexScale, uint64_t Scale, int64_t IndexOffset,
426+
ExtensionKind Extension, unsigned int ptrSize);
427+
bool checkTerms(const Term* T, const Term* OtherT, int64_t& Off) const;
454428
};
455429
}
456430

@@ -2091,6 +2065,185 @@ bool MemOpt::optimizeGEP64(Instruction* I) const {
20912065
return Changed;
20922066
}
20932067

2068+
// getConstantOffset - Return the constant offset between two memory
2069+
// locations.
2070+
bool SymbolicPointer::getConstantOffset(SymbolicPointer& Other, int64_t& Off) {
2071+
Term* DiffTerm = nullptr;
2072+
Term* DiffOtherTerm = nullptr;
2073+
2074+
// Find how many differences there are between the two vectors of terms.
2075+
auto findDifferences = [&](SmallVector<Term, 8>& Terms1, SmallVector<Term, 8>& Terms2) -> int {
2076+
int DiffCount = 0;
2077+
for (unsigned i = 0, e = Terms1.size(); i != e; ++i) {
2078+
bool Found = false;
2079+
for (unsigned j = 0, f = Terms2.size(); !Found && j != f; ++j)
2080+
if (Terms1[i] == Terms2[j])
2081+
Found = true;
2082+
2083+
if (!Found) {
2084+
DiffCount++;
2085+
if (DiffCount > 1)
2086+
break;
2087+
2088+
DiffTerm = &Terms1[i];
2089+
}
2090+
}
2091+
2092+
// If there are no differences, no need to check further.
2093+
if (DiffCount == 0)
2094+
return DiffCount;
2095+
2096+
for (unsigned i = 0, e = Terms2.size(); i != e; ++i) {
2097+
bool Found = false;
2098+
for (unsigned j = 0, f = Terms1.size(); !Found && j != f; ++j)
2099+
if (Terms2[i] == Terms1[j])
2100+
Found = true;
2101+
2102+
if (!Found) {
2103+
DiffOtherTerm = &Terms2[i];
2104+
break;
2105+
}
2106+
}
2107+
2108+
return DiffCount;
2109+
};
2110+
2111+
if (!BasePtr || !Other.BasePtr)
2112+
return true;
2113+
2114+
if (BasePtr != Other.BasePtr &&
2115+
(!isa<ConstantPointerNull>(BasePtr) ||
2116+
!isa<ConstantPointerNull>(Other.BasePtr)))
2117+
return true;
2118+
2119+
if (Terms.size() != Other.Terms.size())
2120+
return true;
2121+
2122+
int DiffCount = findDifferences(Terms, Other.Terms);
2123+
2124+
if (DiffCount > 1)
2125+
return true;
2126+
2127+
Off = Offset - Other.Offset;
2128+
2129+
if (DiffCount == 0)
2130+
return false;
2131+
2132+
if (checkTerms(DiffTerm, DiffOtherTerm, Off))
2133+
return true;
2134+
2135+
return false;
2136+
}
2137+
2138+
// Try to match the pattern that can't be processed by the current decomposePointer algorithm.
2139+
// First chain:
2140+
// %145 = add nsw i32 %102, 1
2141+
// %146 = sub nsw i32 %145, %const_reg_dword18
2142+
//
2143+
// Second chain:
2144+
// %176 = add nsw i32 %102, 2
2145+
// %177 = sub nsw i32 %176, %const_reg_dword18
2146+
bool SymbolicPointer::checkTerms(const Term* T, const Term* OtherT, int64_t& Off) const {
2147+
bool IsPositive = true;
2148+
size_t OpNum = 0;
2149+
2150+
// Check that the instructions are add or sub with nsw flag.
2151+
auto checkInstructions = [&](const BinaryOperator* Inst0, const BinaryOperator* Inst1) -> bool {
2152+
if (!Inst0 || !Inst1)
2153+
return true;
2154+
2155+
if (Inst1->getOpcode() != Inst0->getOpcode())
2156+
return true;
2157+
2158+
if (Inst0->getOpcode() != Instruction::Add && Inst0->getOpcode() != Instruction::Sub)
2159+
return true;
2160+
2161+
if (!Inst0->hasNoSignedWrap() || !Inst1->hasNoSignedWrap())
2162+
return true;
2163+
2164+
if (Inst0->getOperand(0) != Inst1->getOperand(0) &&
2165+
Inst0->getOperand(1) != Inst1->getOperand(1))
2166+
return true;
2167+
2168+
if (Inst0->getOpcode() == Instruction::Sub) {
2169+
if (Inst0->getOperand(0) == Inst1->getOperand(0)) {
2170+
OpNum = 1;
2171+
IsPositive = !IsPositive;
2172+
} else {
2173+
OpNum = 0;
2174+
}
2175+
} else {
2176+
if (Inst0->getOperand(1) == Inst1->getOperand(1)) {
2177+
OpNum = 0;
2178+
} else {
2179+
OpNum = 1;
2180+
}
2181+
}
2182+
2183+
return false;
2184+
};
2185+
2186+
if (!T || !OtherT)
2187+
return true;
2188+
2189+
auto* Inst = dyn_cast<BinaryOperator>(T->Idx.getPointer());
2190+
auto* OtherInst = dyn_cast<BinaryOperator>(OtherT->Idx.getPointer());
2191+
if (checkInstructions(Inst, OtherInst))
2192+
return true;
2193+
2194+
auto InstOp0 = dyn_cast<BinaryOperator>(Inst->getOperand(OpNum));
2195+
auto OtherInstOp0 = dyn_cast<BinaryOperator>(OtherInst->getOperand(OpNum));
2196+
if (checkInstructions(InstOp0, OtherInstOp0))
2197+
return true;
2198+
2199+
auto ConstInt = dyn_cast<ConstantInt>(InstOp0->getOperand(1));
2200+
auto OtherConstInt = dyn_cast<ConstantInt>(OtherInstOp0->getOperand(1));
2201+
if (!ConstInt || !OtherConstInt)
2202+
return true;
2203+
2204+
int64_t NewScale = T->Scale;
2205+
int64_t NewOtherScale = OtherT->Scale;
2206+
if (!IsPositive) {
2207+
NewScale = -NewScale;
2208+
NewOtherScale = -NewOtherScale;
2209+
}
2210+
2211+
Off += ConstInt->getSExtValue() * NewScale - OtherConstInt->getSExtValue() * NewOtherScale;
2212+
return false;
2213+
}
2214+
2215+
// Save Term in the vector of terms.
2216+
void SymbolicPointer::saveTerm(Value* Src, int64_t IndexScale, uint64_t Scale, int64_t IndexOffset, ExtensionKind Extension, unsigned int ptrSize) {;
2217+
this->Offset += IndexOffset * Scale;
2218+
Scale *= IndexScale;
2219+
2220+
SymbolicIndex Idx(Src, Extension);
2221+
2222+
// If we already had an occurrence of this index variable, merge this
2223+
// scale into it. For example, we want to handle:
2224+
// A[x][x] -> x*16 + x*4 -> x*20
2225+
// This also ensures that 'x' only appears in the index list once.
2226+
for (unsigned i = 0, e = this->Terms.size(); i != e; ++i) {
2227+
if (this->Terms[i].Idx == Idx) {
2228+
Scale += this->Terms[i].Scale;
2229+
this->Terms.erase(this->Terms.begin() + i);
2230+
break;
2231+
}
2232+
}
2233+
2234+
// Make sure that we have a scale that makes sense for this target's
2235+
// pointer size.
2236+
if (unsigned ShiftBits = 64 - ptrSize) {
2237+
Scale <<= ShiftBits;
2238+
Scale = (int64_t)Scale >> ShiftBits;
2239+
}
2240+
2241+
if (Scale) {
2242+
Term Entry = { Idx, int64_t(Scale) };
2243+
this->Terms.push_back(Entry);
2244+
}
2245+
}
2246+
20942247
Value*
20952248
SymbolicPointer::getLinearExpression(Value* V, APInt& Scale, APInt& Offset,
20962249
ExtensionKind& Extension, unsigned Depth,
@@ -2247,34 +2400,7 @@ SymbolicPointer::decomposePointer(const Value* Ptr, SymbolicPointer& SymPtr,
22472400
APInt IndexScale(Width, 0), IndexOffset(Width, 0);
22482401
Src = getLinearExpression(Src, IndexScale, IndexOffset, Extension,
22492402
0U, DL);
2250-
SymPtr.Offset += IndexOffset.getSExtValue() * Scale;
2251-
Scale *= IndexScale.getSExtValue();
2252-
2253-
SymbolicIndex Idx(Src, Extension);
2254-
2255-
// If we already had an occurrence of this index variable, merge this
2256-
// scale into it. For example, we want to handle:
2257-
// A[x][x] -> x*16 + x*4 -> x*20
2258-
// This also ensures that 'x' only appears in the index list once.
2259-
for (unsigned i = 0, e = SymPtr.Terms.size(); i != e; ++i) {
2260-
if (SymPtr.Terms[i].Idx == Idx) {
2261-
Scale += SymPtr.Terms[i].Scale;
2262-
SymPtr.Terms.erase(SymPtr.Terms.begin() + i);
2263-
break;
2264-
}
2265-
}
2266-
2267-
// Make sure that we have a scale that makes sense for this target's
2268-
// pointer size.
2269-
if (unsigned ShiftBits = 64 - ptrSize) {
2270-
Scale <<= ShiftBits;
2271-
Scale = (int64_t)Scale >> ShiftBits;
2272-
}
2273-
2274-
if (Scale) {
2275-
Term Entry = { Idx, int64_t(Scale) };
2276-
SymPtr.Terms.push_back(Entry);
2277-
}
2403+
SymPtr.saveTerm(Src, IndexScale.getSExtValue(), Scale, IndexOffset.getSExtValue(), Extension, ptrSize);
22782404

22792405
Ptr = BasePtr;
22802406
}
@@ -2357,34 +2483,7 @@ SymbolicPointer::decomposePointer(const Value* Ptr, SymbolicPointer& SymPtr,
23572483

23582484
// The GEP index scale ("Scale") scales C1*V+C2, yielding (C1*V+C2)*Scale.
23592485
// This gives us an aggregate computation of (C1*Scale)*V + C2*Scale.
2360-
SymPtr.Offset += IndexOffset.getSExtValue() * Scale;
2361-
Scale *= IndexScale.getSExtValue();
2362-
2363-
SymbolicIndex Idx(new_Ind, Extension);
2364-
2365-
// If we already had an occurrence of this index variable, merge this
2366-
// scale into it. For example, we want to handle:
2367-
// A[x][x] -> x*16 + x*4 -> x*20
2368-
// This also ensures that 'x' only appears in the index list once.
2369-
for (unsigned i = 0, e = SymPtr.Terms.size(); i != e; ++i) {
2370-
if (SymPtr.Terms[i].Idx == Idx) {
2371-
Scale += SymPtr.Terms[i].Scale;
2372-
SymPtr.Terms.erase(SymPtr.Terms.begin() + i);
2373-
break;
2374-
}
2375-
}
2376-
2377-
// Make sure that we have a scale that makes sense for this target's
2378-
// pointer size.
2379-
if (unsigned ShiftBits = 64 - ptrSize) {
2380-
Scale <<= ShiftBits;
2381-
Scale = (int64_t)Scale >> ShiftBits;
2382-
}
2383-
2384-
if (Scale) {
2385-
Term Entry = { Idx, int64_t(Scale) };
2386-
SymPtr.Terms.push_back(Entry);
2387-
}
2486+
SymPtr.saveTerm(new_Ind, IndexScale.getSExtValue(), Scale, IndexOffset.getSExtValue(), Extension, ptrSize);
23882487
}
23892488
}
23902489

0 commit comments

Comments
 (0)