diff --git a/llvm/lib/Analysis/Delinearization.cpp b/llvm/lib/Analysis/Delinearization.cpp index b8582b09025a6..42d0eca0d5cb8 100644 --- a/llvm/lib/Analysis/Delinearization.cpp +++ b/llvm/lib/Analysis/Delinearization.cpp @@ -21,8 +21,10 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -397,9 +399,13 @@ void llvm::computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr, Subscripts.push_back(R); } - // Also push in last position the remainder of the last division: it will be - // the access function of the innermost dimension. - Subscripts.push_back(Res); + if (!Res->isZero()) { + // This is only needed when the outermost array size is not known. Res = 0 + // when the outermost array dimension is known, as for example when reading + // array sizes from a local or global declaration. + Subscripts.push_back(Res); + LLVM_DEBUG(dbgs() << "Subscripts push_back Res: " << *Res << "\n"); + } std::reverse(Subscripts.begin(), Subscripts.end()); @@ -590,6 +596,45 @@ bool llvm::findFixedSizeArrayDimensions(ScalarEvolution &SE, const SCEV *Expr, return true; } +static void extractOuterDimFromGlobal(ScalarEvolution &SE, Value *BasePtr, + SmallVectorImpl &Sizes, + const SCEV *ElementSize) { + LLVM_DEBUG(assert(Sizes.size() >= 2 && "Sizes should contain at least" + " the element size and one dimension"); + + for (const SCEV *S : Sizes) + assert(cast(S) && "Only SCEVConstant expected"); + + dbgs() << "extractArrayInfoFromGlobal called with BasePtr: " + << *BasePtr << "\n";); + + auto *GV = dyn_cast(BasePtr); + if (!GV) { + LLVM_DEBUG(dbgs() << "Base pointer is not a global variable, " + << "can't extract outer dimension.\n"); + return false; + } + + LLVM_DEBUG(dbgs() << "Found global variable with type: " + << *GV->getValueType() << "\n"); + + const DataLayout &DL = GV->getParent()->getDataLayout(); + uint64_t SizeInBytes = DL.getTypeAllocSize(GV->getValueType()); + LLVM_DEBUG(dbgs() << "Object size in bytes: " << SizeInBytes << "\n"); + + uint64_t MulConst = 1; + for (const SCEV *S : Sizes) { + const SCEVConstant *SC = cast(S); + MulConst *= SC->getAPInt().getZExtValue(); + } + + uint64_t OuterDim = SizeInBytes / MulConst; + LLVM_DEBUG(dbgs() << "Outer loop dimention = " << SizeInBytes << " / " + << MulConst << " = " << OuterDim << "\n"); + + Sizes.insert(Sizes.begin(), SE.getConstant(ElementSize->getType(), OuterDim)); +} + /// Splits the SCEV into two vectors of SCEVs representing the subscripts and /// sizes of an array access, assuming that the array is a fixed size array. /// @@ -649,19 +694,29 @@ bool llvm::delinearizeFixedSizeArray(ScalarEvolution &SE, const SCEV *Expr, Subscripts.clear(); Sizes.clear(); + const SCEVUnknown *BasePointer = + dyn_cast(SE.getPointerBase(Expr)); + const SCEV *Offset = BasePointer ? SE.getMinusSCEV(Expr, BasePointer) : Expr; + // First step: find the fixed array size. SmallVector ConstSizes; - if (!findFixedSizeArrayDimensions(SE, Expr, ConstSizes, ElementSize)) { + if (!findFixedSizeArrayDimensions(SE, Offset, ConstSizes, ElementSize)) { Sizes.clear(); return false; } // Convert the constant size to SCEV. for (uint64_t Size : ConstSizes) - Sizes.push_back(SE.getConstant(Expr->getType(), Size)); + Sizes.push_back(SE.getConstant(Offset->getType(), Size)); + + // Maybe we can extract the outer dimension from the global variable + // declaration. + bool + if (BasePointer) + extractOuterDimFromGlobal(SE, BasePointer->getValue(), Sizes, ElementSize); // Second step: compute the access functions for each subscript. - computeAccessFunctions(SE, Expr, Subscripts, Sizes); + computeAccessFunctions(SE, Offset, Subscripts, Sizes); return !Subscripts.empty(); } @@ -826,47 +881,65 @@ void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI, // Do not delinearize if we cannot find the base pointer. if (!BasePointer) break; - AccessFn = SE->getMinusSCEV(AccessFn, BasePointer); + const SCEV *Offset = SE->getMinusSCEV(AccessFn, BasePointer); O << "\n"; O << "Inst:" << Inst << "\n"; - O << "AccessFunction: " << *AccessFn << "\n"; + O << "AccessFunction: " << *Offset << "\n"; SmallVector Subscripts, Sizes; auto IsDelinearizationFailed = [&]() { - return Subscripts.size() == 0 || Sizes.size() == 0 || - Subscripts.size() != Sizes.size(); + return Subscripts.size() == 0 || Sizes.size() == 0; }; - delinearize(*SE, AccessFn, Subscripts, Sizes, SE->getElementSize(&Inst)); + delinearize(*SE, Offset, Subscripts, Sizes, SE->getElementSize(&Inst)); + + bool DelinearizedFixedArray = false; if (UseFixedSizeArrayHeuristic && IsDelinearizationFailed()) { Subscripts.clear(); Sizes.clear(); - delinearizeFixedSizeArray(*SE, AccessFn, Subscripts, Sizes, - SE->getElementSize(&Inst)); + DelinearizedFixedArray = delinearizeFixedSizeArray( + *SE, AccessFn, Subscripts, Sizes, SE->getElementSize(&Inst)); } - if (IsDelinearizationFailed()) { - O << "failed to delinearize\n"; - continue; - } + if (IsDelinearizationFailed()) { + O << "failed to delinearize\n"; + continue; + } + + O << "Base offset: " << *BasePointer << "\n"; + O << "ArrayDecl"; + + // Print [Unknown] when the outermost dimension of the array is not known. + // Sizes[NumSizes - 1] is the array element size. + int NumSubscripts = Subscripts.size(); + int NumSizes = Sizes.size(); + if (NumSizes == NumSubscripts) + O << "[UnknownSize]"; + + // Handle different size relationships between Subscripts and Sizes. + if (NumSizes > 0) { + // Print array dimensions (all but the last, which is element size). + for (const SCEV *Size : ArrayRef(Sizes).drop_back()) + O << "[" << *Size << "]"; + + // Print element size (last element in Sizes array). + O << " with elements of " << *Sizes[NumSizes - 1] << " bytes.\n"; + } else { + O << " unknown sizes.\n"; + } + + O << "ArrayRef"; + for (int i = 0; i < NumSubscripts; i++) + O << "[" << *Subscripts[i] << "]"; + O << "\n"; - O << "Base offset: " << *BasePointer << "\n"; - O << "ArrayDecl[UnknownSize]"; - int Size = Subscripts.size(); - for (int i = 0; i < Size - 1; i++) - O << "[" << *Sizes[i] << "]"; - O << " with elements of " << *Sizes[Size - 1] << " bytes.\n"; - - O << "ArrayRef"; - for (int i = 0; i < Size; i++) - O << "[" << *Subscripts[i] << "]"; - O << "\n"; - - bool IsValid = validateDelinearizationResult(*SE, Sizes, Subscripts); - O << "Delinearization validation: " << (IsValid ? "Succeeded" : "Failed") - << "\n"; + bool IsValid = DelinearizedFixedArray + ? true + : validateDelinearizationResult(*SE, Sizes, Subscripts); + O << "Delinearization validation: " << (IsValid ? "Succeeded" : "Failed") + << "\n"; } } diff --git a/llvm/test/Analysis/Delinearization/global_array_bounds.ll b/llvm/test/Analysis/Delinearization/global_array_bounds.ll index 2e13fd66eb930..bb7d544216c93 100644 --- a/llvm/test/Analysis/Delinearization/global_array_bounds.ll +++ b/llvm/test/Analysis/Delinearization/global_array_bounds.ll @@ -18,9 +18,9 @@ define void @test_2d_array(i64 %i, i64 %j, i64 %N, i64 %M) { ; CHECK-NEXT: Inst: %val = load i32, ptr %gepij, align 4 ; CHECK-NEXT: AccessFunction: {{\{\{}}0,+,80}<%for.i>,+,4}<%for.j> ; CHECK-NEXT: Base offset: @test_array_10x20 -; CHECK-NEXT: ArrayDecl[UnknownSize][20] with elements of 4 bytes. +; CHECK-NEXT: ArrayDecl[10][20] with elements of 4 bytes. ; CHECK-NEXT: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>] -; CHECK-NEXT: Delinearization validation: Failed +; CHECK-NEXT: Delinearization validation: Succeeded ; entry: br label %for.i diff --git a/llvm/test/Analysis/Delinearization/validation_large_size.ll b/llvm/test/Analysis/Delinearization/validation_large_size.ll index b798813c302b2..a7ad7678f07fc 100644 --- a/llvm/test/Analysis/Delinearization/validation_large_size.ll +++ b/llvm/test/Analysis/Delinearization/validation_large_size.ll @@ -26,7 +26,7 @@ define void @large_size_fixed(ptr %A) { ; CHECK-NEXT: Base offset: %A ; CHECK-NEXT: ArrayDecl[UnknownSize][256] with elements of 1 bytes. ; CHECK-NEXT: ArrayRef[{0,+,1}<%for.i.header>][{0,+,1}<%for.j>] -; CHECK-NEXT: Delinearization validation: Failed +; CHECK-NEXT: Delinearization validation: Succeeded ; entry: br label %for.i.header @@ -151,7 +151,7 @@ define void @elementsize_cause_ovfl(ptr %A) { ; CHECK-NEXT: Base offset: %A ; CHECK-NEXT: ArrayDecl[UnknownSize][256] with elements of 8 bytes. ; CHECK-NEXT: ArrayRef[{0,+,1}<%for.i.header>][{0,+,1}<%for.j>] -; CHECK-NEXT: Delinearization validation: Failed +; CHECK-NEXT: Delinearization validation: Succeeded ; entry: br label %for.i.header