[Polly] Remove support for code generated by gfortran+DragonEgg.
DragonEgg is not maintained anymore, hence there is no need for this functionality. Fixes llvm.org/PR52173
This commit is contained in:
parent
a5e52ce3f2
commit
19db33c06e
|
@ -21,3 +21,7 @@ In Polly 14 the following important changes have been incorporated.
|
|||
This will agressively try to fuse any loop regardless of
|
||||
profitability. The is what users might have expected what
|
||||
-polly-opt-fusion=max would do.
|
||||
|
||||
- Support for gfortran-generated code has been removed. This includes
|
||||
Fortran Array Descriptors (-polly-detect-fortran-arrays) and the
|
||||
-polly-rewrite-byref-params pass.
|
||||
|
|
|
@ -78,13 +78,6 @@ public:
|
|||
|
||||
void addParameters(__isl_take isl_set *Context);
|
||||
|
||||
/// Create Values which hold the sizes of the outermost dimension of all
|
||||
/// Fortran arrays in the current scop.
|
||||
///
|
||||
/// @returns False, if a problem occurred and a Fortran array was not
|
||||
/// materialized. True otherwise.
|
||||
bool materializeFortranArrayOutermostDimension();
|
||||
|
||||
/// Generate code that evaluates @p Condition at run-time.
|
||||
///
|
||||
/// This function is typically called to generate the LLVM-IR for the
|
||||
|
|
|
@ -43,7 +43,6 @@ llvm::Pass *createPolyhedralInfoPass();
|
|||
llvm::Pass *createScopDetectionWrapperPassPass();
|
||||
llvm::Pass *createScopInfoRegionPassPass();
|
||||
llvm::Pass *createScopInfoWrapperPassPass();
|
||||
llvm::Pass *createRewriteByrefParamsWrapperPass();
|
||||
llvm::Pass *createIslAstInfoWrapperPassPass();
|
||||
llvm::Pass *createCodeGenerationPass();
|
||||
#ifdef GPU_CODEGEN
|
||||
|
@ -88,7 +87,6 @@ struct PollyForcePassLinking {
|
|||
polly::createScopInfoRegionPassPass();
|
||||
polly::createPollyCanonicalizePass();
|
||||
polly::createPolyhedralInfoPass();
|
||||
polly::createRewriteByrefParamsWrapperPass();
|
||||
polly::createIslAstInfoWrapperPassPass();
|
||||
polly::createCodeGenerationPass();
|
||||
#ifdef GPU_CODEGEN
|
||||
|
@ -117,7 +115,6 @@ void initializeJSONExporterPass(llvm::PassRegistry &);
|
|||
void initializeJSONImporterPass(llvm::PassRegistry &);
|
||||
void initializeIslAstInfoWrapperPassPass(llvm::PassRegistry &);
|
||||
void initializeCodeGenerationPass(llvm::PassRegistry &);
|
||||
void initializeRewriteByrefParamsWrapperPassPass(llvm::PassRegistry &);
|
||||
#ifdef GPU_CODEGEN
|
||||
void initializePPCGCodeGenerationPass(llvm::PassRegistry &);
|
||||
void initializeManagedMemoryRewritePassPass(llvm::PassRegistry &);
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
//===- RewriteByReferenceParameters.h -------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef POLLY_REWRITEBYREFERENCEPARAMETERS_H
|
||||
#define POLLY_REWRITEBYREFERENCEPARAMETERS_H
|
||||
|
||||
#include "polly/ScopPass.h"
|
||||
|
||||
namespace llvm {
|
||||
class PassRegistry;
|
||||
class Pass;
|
||||
class raw_ostream;
|
||||
} // namespace llvm
|
||||
|
||||
namespace polly {
|
||||
llvm::Pass *createRewriteByrefParamsWrapperPass();
|
||||
|
||||
struct RewriteByrefParamsPass : llvm::PassInfoMixin<RewriteByrefParamsPass> {
|
||||
RewriteByrefParamsPass() {}
|
||||
|
||||
llvm::PreservedAnalyses run(llvm::Function &F,
|
||||
llvm::FunctionAnalysisManager &FAM);
|
||||
};
|
||||
|
||||
} // namespace polly
|
||||
|
||||
namespace llvm {
|
||||
void initializeRewriteByrefParamsWrapperPassPass(llvm::PassRegistry &);
|
||||
} // namespace llvm
|
||||
|
||||
#endif /* POLLY_REWRITEBYREFERENCEPARAMETERS_H */
|
|
@ -74,65 +74,6 @@ class ScopBuilder {
|
|||
/// only be simplified later on.
|
||||
RecordedAssumptionsTy RecordedAssumptions;
|
||||
|
||||
// Methods for pattern matching against Fortran code generated by dragonegg.
|
||||
// @{
|
||||
|
||||
/// Try to match for the descriptor of a Fortran array whose allocation
|
||||
/// is not visible. That is, we can see the load/store into the memory, but
|
||||
/// we don't actually know where the memory is allocated. If ALLOCATE had been
|
||||
/// called on the Fortran array, then we will see the lowered malloc() call.
|
||||
/// If not, this is dubbed as an "invisible allocation".
|
||||
///
|
||||
/// "<descriptor>" is the descriptor of the Fortran array.
|
||||
///
|
||||
/// Pattern match for "@descriptor":
|
||||
/// 1. %mem = load double*, double** bitcast (%"struct.array1_real(kind=8)"*
|
||||
/// <descriptor> to double**), align 32
|
||||
///
|
||||
/// 2. [%slot = getelementptr inbounds i8, i8* %mem, i64 <index>]
|
||||
/// 2 is optional because if you are writing to the 0th index, you don't
|
||||
/// need a GEP.
|
||||
///
|
||||
/// 3.1 store/load <memtype> <val>, <memtype>* %slot
|
||||
/// 3.2 store/load <memtype> <val>, <memtype>* %mem
|
||||
///
|
||||
/// @see polly::MemoryAccess, polly::ScopArrayInfo
|
||||
///
|
||||
/// @note assumes -polly-canonicalize has been run.
|
||||
///
|
||||
/// @param Inst The LoadInst/StoreInst that accesses the memory.
|
||||
///
|
||||
/// @returns Reference to <descriptor> on success, nullptr on failure.
|
||||
Value *findFADAllocationInvisible(MemAccInst Inst);
|
||||
|
||||
/// Try to match for the descriptor of a Fortran array whose allocation
|
||||
/// call is visible. When we have a Fortran array, we try to look for a
|
||||
/// Fortran array where we can see the lowered ALLOCATE call. ALLOCATE
|
||||
/// is materialized as a malloc(...) which we pattern match for.
|
||||
///
|
||||
/// Pattern match for "%untypedmem":
|
||||
/// 1. %untypedmem = i8* @malloc(...)
|
||||
///
|
||||
/// 2. %typedmem = bitcast i8* %untypedmem to <memtype>
|
||||
///
|
||||
/// 3. [%slot = getelementptr inbounds i8, i8* %typedmem, i64 <index>]
|
||||
/// 3 is optional because if you are writing to the 0th index, you don't
|
||||
/// need a GEP.
|
||||
///
|
||||
/// 4.1 store/load <memtype> <val>, <memtype>* %slot, align 8
|
||||
/// 4.2 store/load <memtype> <val>, <memtype>* %mem, align 8
|
||||
///
|
||||
/// @see polly::MemoryAccess, polly::ScopArrayInfo
|
||||
///
|
||||
/// @note assumes -polly-canonicalize has been run.
|
||||
///
|
||||
/// @param Inst The LoadInst/StoreInst that accesses the memory.
|
||||
///
|
||||
/// @returns Reference to %untypedmem on success, nullptr on failure.
|
||||
Value *findFADAllocationVisible(MemAccInst Inst);
|
||||
|
||||
// @}
|
||||
|
||||
// Build the SCoP for Region @p R.
|
||||
void buildScop(Region &R, AssumptionCache &AC);
|
||||
|
||||
|
@ -417,9 +358,6 @@ class ScopBuilder {
|
|||
/// all memory accesses have been modeled and canonicalized.
|
||||
void assumeNoOutOfBounds();
|
||||
|
||||
/// Mark arrays that have memory accesses with FortranArrayDescriptor.
|
||||
void markFortranArrays();
|
||||
|
||||
/// Build the alias checks for this SCoP.
|
||||
bool buildAliasChecks();
|
||||
|
||||
|
|
|
@ -264,16 +264,6 @@ public:
|
|||
/// with old sizes
|
||||
bool updateSizes(ArrayRef<const SCEV *> Sizes, bool CheckConsistency = true);
|
||||
|
||||
/// Make the ScopArrayInfo model a Fortran array.
|
||||
/// It receives the Fortran array descriptor and stores this.
|
||||
/// It also adds a piecewise expression for the outermost dimension
|
||||
/// since this information is available for Fortran arrays at runtime.
|
||||
void applyAndSetFAD(Value *FAD);
|
||||
|
||||
/// Get the FortranArrayDescriptor corresponding to this array if it exists,
|
||||
/// nullptr otherwise.
|
||||
Value *getFortranArrayDescriptor() const { return this->FAD; }
|
||||
|
||||
/// Set the base pointer to @p BP.
|
||||
void setBasePtr(Value *BP) { BasePtr = BP; }
|
||||
|
||||
|
@ -440,10 +430,6 @@ private:
|
|||
|
||||
/// The scop this SAI object belongs to.
|
||||
Scop &S;
|
||||
|
||||
/// If this array models a Fortran array, then this points
|
||||
/// to the Fortran array descriptor.
|
||||
Value *FAD = nullptr;
|
||||
};
|
||||
|
||||
/// Represent memory accesses in statements.
|
||||
|
@ -636,13 +622,6 @@ private:
|
|||
|
||||
/// Updated access relation read from JSCOP file.
|
||||
isl::map NewAccessRelation;
|
||||
|
||||
/// Fortran arrays whose sizes are not statically known are stored in terms
|
||||
/// of a descriptor struct. This maintains a raw pointer to the memory,
|
||||
/// along with auxiliary fields with information such as dimensions.
|
||||
/// We hold a reference to the descriptor corresponding to a MemoryAccess
|
||||
/// into a Fortran array. FAD for "Fortran Array Descriptor"
|
||||
AssertingVH<Value> FAD;
|
||||
// @}
|
||||
|
||||
isl::basic_map createBasicAccessMap(ScopStmt *Statement);
|
||||
|
@ -935,10 +914,6 @@ public:
|
|||
/// the dimension of the innermost loop containing the statement.
|
||||
isl::set getStride(isl::map Schedule) const;
|
||||
|
||||
/// Get the FortranArrayDescriptor corresponding to this memory access if
|
||||
/// it exists, and nullptr otherwise.
|
||||
Value *getFortranArrayDescriptor() const { return this->FAD; }
|
||||
|
||||
/// Is the stride of the access equal to a certain width? Schedule is a map
|
||||
/// from the statement to a schedule where the innermost dimension is the
|
||||
/// dimension of the innermost loop containing the statement.
|
||||
|
@ -1061,10 +1036,6 @@ public:
|
|||
/// Get the reduction type of this access
|
||||
ReductionType getReductionType() const { return RedType; }
|
||||
|
||||
/// Set the array descriptor corresponding to the Array on which the
|
||||
/// memory access is performed.
|
||||
void setFortranArrayDescriptor(Value *FAD);
|
||||
|
||||
/// Update the original access relation.
|
||||
///
|
||||
/// We need to update the original access relation during scop construction,
|
||||
|
|
|
@ -129,11 +129,6 @@ static cl::opt<std::string> UserContextStr(
|
|||
cl::desc("Provide additional constraints on the context parameters"),
|
||||
cl::init(""), cl::cat(PollyCategory));
|
||||
|
||||
static cl::opt<bool> DetectFortranArrays(
|
||||
"polly-detect-fortran-arrays",
|
||||
cl::desc("Detect Fortran arrays and use this for code generation"),
|
||||
cl::Hidden, cl::init(false), cl::cat(PollyCategory));
|
||||
|
||||
static cl::opt<bool> DetectReductions("polly-detect-reductions",
|
||||
cl::desc("Detect and exploit reductions"),
|
||||
cl::Hidden, cl::ZeroOrMore,
|
||||
|
@ -1333,189 +1328,6 @@ void ScopBuilder::buildEscapingDependences(Instruction *Inst) {
|
|||
ensureValueWrite(Inst);
|
||||
}
|
||||
|
||||
/// Check that a value is a Fortran Array descriptor.
|
||||
///
|
||||
/// We check if V has the following structure:
|
||||
/// %"struct.array1_real(kind=8)" = type { i8*, i<zz>, i<zz>,
|
||||
/// [<num> x %struct.descriptor_dimension] }
|
||||
///
|
||||
///
|
||||
/// %struct.descriptor_dimension = type { i<zz>, i<zz>, i<zz> }
|
||||
///
|
||||
/// 1. V's type name starts with "struct.array"
|
||||
/// 2. V's type has layout as shown.
|
||||
/// 3. Final member of V's type has name "struct.descriptor_dimension",
|
||||
/// 4. "struct.descriptor_dimension" has layout as shown.
|
||||
/// 5. Consistent use of i<zz> where <zz> is some fixed integer number.
|
||||
///
|
||||
/// We are interested in such types since this is the code that dragonegg
|
||||
/// generates for Fortran array descriptors.
|
||||
///
|
||||
/// @param V the Value to be checked.
|
||||
///
|
||||
/// @returns True if V is a Fortran array descriptor, False otherwise.
|
||||
bool isFortranArrayDescriptor(Value *V) {
|
||||
PointerType *PTy = dyn_cast<PointerType>(V->getType());
|
||||
|
||||
if (!PTy)
|
||||
return false;
|
||||
|
||||
Type *Ty = PTy->getElementType();
|
||||
assert(Ty && "Ty expected to be initialized");
|
||||
auto *StructArrTy = dyn_cast<StructType>(Ty);
|
||||
|
||||
if (!(StructArrTy && StructArrTy->hasName()))
|
||||
return false;
|
||||
|
||||
if (!StructArrTy->getName().startswith("struct.array"))
|
||||
return false;
|
||||
|
||||
if (StructArrTy->getNumElements() != 4)
|
||||
return false;
|
||||
|
||||
const ArrayRef<Type *> ArrMemberTys = StructArrTy->elements();
|
||||
|
||||
// i8* match
|
||||
if (ArrMemberTys[0] != Type::getInt8PtrTy(V->getContext()))
|
||||
return false;
|
||||
|
||||
// Get a reference to the int type and check that all the members
|
||||
// share the same int type
|
||||
Type *IntTy = ArrMemberTys[1];
|
||||
if (ArrMemberTys[2] != IntTy)
|
||||
return false;
|
||||
|
||||
// type: [<num> x %struct.descriptor_dimension]
|
||||
ArrayType *DescriptorDimArrayTy = dyn_cast<ArrayType>(ArrMemberTys[3]);
|
||||
if (!DescriptorDimArrayTy)
|
||||
return false;
|
||||
|
||||
// type: %struct.descriptor_dimension := type { ixx, ixx, ixx }
|
||||
StructType *DescriptorDimTy =
|
||||
dyn_cast<StructType>(DescriptorDimArrayTy->getElementType());
|
||||
|
||||
if (!(DescriptorDimTy && DescriptorDimTy->hasName()))
|
||||
return false;
|
||||
|
||||
if (DescriptorDimTy->getName() != "struct.descriptor_dimension")
|
||||
return false;
|
||||
|
||||
if (DescriptorDimTy->getNumElements() != 3)
|
||||
return false;
|
||||
|
||||
for (auto MemberTy : DescriptorDimTy->elements()) {
|
||||
if (MemberTy != IntTy)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Value *ScopBuilder::findFADAllocationVisible(MemAccInst Inst) {
|
||||
// match: 4.1 & 4.2 store/load
|
||||
if (!isa<LoadInst>(Inst) && !isa<StoreInst>(Inst))
|
||||
return nullptr;
|
||||
|
||||
// match: 4
|
||||
if (Inst.getAlignment() != 8)
|
||||
return nullptr;
|
||||
|
||||
Value *Address = Inst.getPointerOperand();
|
||||
|
||||
const BitCastInst *Bitcast = nullptr;
|
||||
// [match: 3]
|
||||
if (auto *Slot = dyn_cast<GetElementPtrInst>(Address)) {
|
||||
Value *TypedMem = Slot->getPointerOperand();
|
||||
// match: 2
|
||||
Bitcast = dyn_cast<BitCastInst>(TypedMem);
|
||||
} else {
|
||||
// match: 2
|
||||
Bitcast = dyn_cast<BitCastInst>(Address);
|
||||
}
|
||||
|
||||
if (!Bitcast)
|
||||
return nullptr;
|
||||
|
||||
auto *MallocMem = Bitcast->getOperand(0);
|
||||
|
||||
// match: 1
|
||||
auto *MallocCall = dyn_cast<CallInst>(MallocMem);
|
||||
if (!MallocCall)
|
||||
return nullptr;
|
||||
|
||||
Function *MallocFn = MallocCall->getCalledFunction();
|
||||
if (!(MallocFn && MallocFn->hasName() && MallocFn->getName() == "malloc"))
|
||||
return nullptr;
|
||||
|
||||
// Find all uses the malloc'd memory.
|
||||
// We are looking for a "store" into a struct with the type being the Fortran
|
||||
// descriptor type
|
||||
for (auto user : MallocMem->users()) {
|
||||
/// match: 5
|
||||
auto *MallocStore = dyn_cast<StoreInst>(user);
|
||||
if (!MallocStore)
|
||||
continue;
|
||||
|
||||
auto *DescriptorGEP =
|
||||
dyn_cast<GEPOperator>(MallocStore->getPointerOperand());
|
||||
if (!DescriptorGEP)
|
||||
continue;
|
||||
|
||||
// match: 5
|
||||
auto DescriptorType =
|
||||
dyn_cast<StructType>(DescriptorGEP->getSourceElementType());
|
||||
if (!(DescriptorType && DescriptorType->hasName()))
|
||||
continue;
|
||||
|
||||
Value *Descriptor = dyn_cast<Value>(DescriptorGEP->getPointerOperand());
|
||||
|
||||
if (!Descriptor)
|
||||
continue;
|
||||
|
||||
if (!isFortranArrayDescriptor(Descriptor))
|
||||
continue;
|
||||
|
||||
return Descriptor;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *ScopBuilder::findFADAllocationInvisible(MemAccInst Inst) {
|
||||
// match: 3
|
||||
if (!isa<LoadInst>(Inst) && !isa<StoreInst>(Inst))
|
||||
return nullptr;
|
||||
|
||||
Value *Slot = Inst.getPointerOperand();
|
||||
|
||||
LoadInst *MemLoad = nullptr;
|
||||
// [match: 2]
|
||||
if (auto *SlotGEP = dyn_cast<GetElementPtrInst>(Slot)) {
|
||||
// match: 1
|
||||
MemLoad = dyn_cast<LoadInst>(SlotGEP->getPointerOperand());
|
||||
} else {
|
||||
// match: 1
|
||||
MemLoad = dyn_cast<LoadInst>(Slot);
|
||||
}
|
||||
|
||||
if (!MemLoad)
|
||||
return nullptr;
|
||||
|
||||
auto *BitcastOperator =
|
||||
dyn_cast<BitCastOperator>(MemLoad->getPointerOperand());
|
||||
if (!BitcastOperator)
|
||||
return nullptr;
|
||||
|
||||
Value *Descriptor = dyn_cast<Value>(BitcastOperator->getOperand(0));
|
||||
if (!Descriptor)
|
||||
return nullptr;
|
||||
|
||||
if (!isFortranArrayDescriptor(Descriptor))
|
||||
return nullptr;
|
||||
|
||||
return Descriptor;
|
||||
}
|
||||
|
||||
void ScopBuilder::addRecordedAssumptions() {
|
||||
for (auto &AS : llvm::reverse(RecordedAssumptions)) {
|
||||
|
||||
|
@ -2350,17 +2162,8 @@ void ScopBuilder::addArrayAccess(ScopStmt *Stmt, MemAccInst MemAccInst,
|
|||
ArrayRef<const SCEV *> Sizes,
|
||||
Value *AccessValue) {
|
||||
ArrayBasePointers.insert(BaseAddress);
|
||||
auto *MemAccess = addMemoryAccess(Stmt, MemAccInst, AccType, BaseAddress,
|
||||
ElementType, IsAffine, AccessValue,
|
||||
Subscripts, Sizes, MemoryKind::Array);
|
||||
|
||||
if (!DetectFortranArrays)
|
||||
return;
|
||||
|
||||
if (Value *FAD = findFADAllocationInvisible(MemAccInst))
|
||||
MemAccess->setFortranArrayDescriptor(FAD);
|
||||
else if (Value *FAD = findFADAllocationVisible(MemAccInst))
|
||||
MemAccess->setFortranArrayDescriptor(FAD);
|
||||
addMemoryAccess(Stmt, MemAccInst, AccType, BaseAddress, ElementType, IsAffine,
|
||||
AccessValue, Subscripts, Sizes, MemoryKind::Array);
|
||||
}
|
||||
|
||||
/// Check if @p Expr is divisible by @p Size.
|
||||
|
@ -2490,29 +2293,11 @@ void ScopBuilder::foldSizeConstantsToRight() {
|
|||
}
|
||||
}
|
||||
|
||||
void ScopBuilder::markFortranArrays() {
|
||||
for (ScopStmt &Stmt : *scop) {
|
||||
for (MemoryAccess *MemAcc : Stmt) {
|
||||
Value *FAD = MemAcc->getFortranArrayDescriptor();
|
||||
if (!FAD)
|
||||
continue;
|
||||
|
||||
// TODO: const_cast-ing to edit
|
||||
ScopArrayInfo *SAI =
|
||||
const_cast<ScopArrayInfo *>(MemAcc->getLatestScopArrayInfo());
|
||||
assert(SAI && "memory access into a Fortran array does not "
|
||||
"have an associated ScopArrayInfo");
|
||||
SAI->applyAndSetFAD(FAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScopBuilder::finalizeAccesses() {
|
||||
updateAccessDimensionality();
|
||||
foldSizeConstantsToRight();
|
||||
foldAccessRelations();
|
||||
assumeNoOutOfBounds();
|
||||
markFortranArrays();
|
||||
}
|
||||
|
||||
void ScopBuilder::updateAccessDimensionality() {
|
||||
|
|
|
@ -298,32 +298,6 @@ void ScopArrayInfo::updateElementType(Type *NewElementType) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Make the ScopArrayInfo model a Fortran Array
|
||||
void ScopArrayInfo::applyAndSetFAD(Value *FAD) {
|
||||
assert(FAD && "got invalid Fortran array descriptor");
|
||||
if (this->FAD) {
|
||||
assert(this->FAD == FAD &&
|
||||
"receiving different array descriptors for same array");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(DimensionSizesPw.size() > 0 && DimensionSizesPw[0].is_null());
|
||||
assert(!this->FAD);
|
||||
this->FAD = FAD;
|
||||
|
||||
isl::space Space(S.getIslCtx(), 1, 0);
|
||||
|
||||
std::string param_name = getName();
|
||||
param_name += "_fortranarr_size";
|
||||
isl::id IdPwAff = isl::id::alloc(S.getIslCtx(), param_name, this);
|
||||
|
||||
Space = Space.set_dim_id(isl::dim::param, 0, IdPwAff);
|
||||
isl::pw_aff PwAff =
|
||||
isl::aff::var_on_domain(isl::local_space(Space), isl::dim::param, 0);
|
||||
|
||||
DimensionSizesPw[0] = PwAff;
|
||||
}
|
||||
|
||||
bool ScopArrayInfo::updateSizes(ArrayRef<const SCEV *> NewSizes,
|
||||
bool CheckConsistency) {
|
||||
int SharedDims = std::min(NewSizes.size(), DimensionSizes.size());
|
||||
|
@ -372,12 +346,8 @@ LLVM_DUMP_METHOD void ScopArrayInfo::dump() const { print(errs()); }
|
|||
void ScopArrayInfo::print(raw_ostream &OS, bool SizeAsPwAff) const {
|
||||
OS.indent(8) << *getElementType() << " " << getName();
|
||||
unsigned u = 0;
|
||||
// If this is a Fortran array, then we can print the outermost dimension
|
||||
// as a isl_pw_aff even though there is no SCEV information.
|
||||
bool IsOutermostSizeKnown = SizeAsPwAff && FAD;
|
||||
|
||||
if (!IsOutermostSizeKnown && getNumberOfDimensions() > 0 &&
|
||||
!getDimensionSize(0)) {
|
||||
if (getNumberOfDimensions() > 0 && !getDimensionSize(0)) {
|
||||
OS << "[*]";
|
||||
u++;
|
||||
}
|
||||
|
@ -894,7 +864,7 @@ MemoryAccess::MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst,
|
|||
Sizes(Sizes.begin(), Sizes.end()), AccessInstruction(AccessInst),
|
||||
AccessValue(AccessValue), IsAffine(Affine),
|
||||
Subscripts(Subscripts.begin(), Subscripts.end()), AccessRelation(),
|
||||
NewAccessRelation(), FAD(nullptr) {
|
||||
NewAccessRelation() {
|
||||
static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"};
|
||||
const std::string Access = TypeStrings[AccType] + utostr(Stmt->size());
|
||||
|
||||
|
@ -904,8 +874,7 @@ MemoryAccess::MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst,
|
|||
|
||||
MemoryAccess::MemoryAccess(ScopStmt *Stmt, AccessType AccType, isl::map AccRel)
|
||||
: Kind(MemoryKind::Array), AccType(AccType), Statement(Stmt),
|
||||
InvalidDomain(), AccessRelation(), NewAccessRelation(AccRel),
|
||||
FAD(nullptr) {
|
||||
InvalidDomain(), AccessRelation(), NewAccessRelation(AccRel) {
|
||||
isl::id ArrayInfoId = NewAccessRelation.get_tuple_id(isl::dim::out);
|
||||
auto *SAI = ScopArrayInfo::getFromId(ArrayInfoId);
|
||||
Sizes.push_back(nullptr);
|
||||
|
@ -949,8 +918,6 @@ raw_ostream &polly::operator<<(raw_ostream &OS,
|
|||
return OS;
|
||||
}
|
||||
|
||||
void MemoryAccess::setFortranArrayDescriptor(Value *FAD) { this->FAD = FAD; }
|
||||
|
||||
void MemoryAccess::print(raw_ostream &OS) const {
|
||||
switch (AccType) {
|
||||
case READ:
|
||||
|
@ -966,11 +933,6 @@ void MemoryAccess::print(raw_ostream &OS) const {
|
|||
|
||||
OS << "[Reduction Type: " << getReductionType() << "] ";
|
||||
|
||||
if (FAD) {
|
||||
OS << "[Fortran array descriptor: " << FAD->getName();
|
||||
OS << "] ";
|
||||
};
|
||||
|
||||
OS << "[Scalar: " << isScalarKind() << "]\n";
|
||||
OS.indent(16) << getOriginalAccessRelationStr() << ";\n";
|
||||
if (hasNewAccessRelation())
|
||||
|
@ -1539,41 +1501,6 @@ void Scop::addParameterBounds() {
|
|||
intersectDefinedBehavior(Context, AS_ASSUMPTION);
|
||||
}
|
||||
|
||||
static std::vector<isl::id> getFortranArrayIds(Scop::array_range Arrays) {
|
||||
std::vector<isl::id> OutermostSizeIds;
|
||||
for (auto Array : Arrays) {
|
||||
// To check if an array is a Fortran array, we check if it has a isl_pw_aff
|
||||
// for its outermost dimension. Fortran arrays will have this since the
|
||||
// outermost dimension size can be picked up from their runtime description.
|
||||
// TODO: actually need to check if it has a FAD, but for now this works.
|
||||
if (Array->getNumberOfDimensions() > 0) {
|
||||
isl::pw_aff PwAff = Array->getDimensionSizePw(0);
|
||||
if (PwAff.is_null())
|
||||
continue;
|
||||
|
||||
isl::id Id = PwAff.get_dim_id(isl::dim::param, 0);
|
||||
assert(!Id.is_null() &&
|
||||
"Invalid Id for PwAff expression in Fortran array");
|
||||
OutermostSizeIds.push_back(Id);
|
||||
}
|
||||
}
|
||||
return OutermostSizeIds;
|
||||
}
|
||||
|
||||
// The FORTRAN array size parameters are known to be non-negative.
|
||||
static isl::set boundFortranArrayParams(isl::set Context,
|
||||
Scop::array_range Arrays) {
|
||||
std::vector<isl::id> OutermostSizeIds;
|
||||
OutermostSizeIds = getFortranArrayIds(Arrays);
|
||||
|
||||
for (isl::id Id : OutermostSizeIds) {
|
||||
int dim = Context.find_dim_by_id(isl::dim::param, Id);
|
||||
Context = Context.lower_bound_si(isl::dim::param, dim, 0);
|
||||
}
|
||||
|
||||
return Context;
|
||||
}
|
||||
|
||||
void Scop::realignParams() {
|
||||
if (PollyIgnoreParamBounds)
|
||||
return;
|
||||
|
@ -1586,9 +1513,6 @@ void Scop::realignParams() {
|
|||
AssumedContext = AssumedContext.align_params(Space);
|
||||
InvalidContext = InvalidContext.align_params(Space);
|
||||
|
||||
// Bound the size of the fortran array dimensions.
|
||||
Context = boundFortranArrayParams(Context, arrays());
|
||||
|
||||
// As all parameters are known add bounds to them.
|
||||
addParameterBounds();
|
||||
|
||||
|
@ -1901,11 +1825,8 @@ isl::set Scop::getContext() const { return Context; }
|
|||
isl::space Scop::getParamSpace() const { return getContext().get_space(); }
|
||||
|
||||
isl::space Scop::getFullParamSpace() const {
|
||||
std::vector<isl::id> FortranIDs;
|
||||
FortranIDs = getFortranArrayIds(arrays());
|
||||
|
||||
isl::space Space = isl::space::params_alloc(
|
||||
getIslCtx(), ParameterIds.size() + FortranIDs.size());
|
||||
isl::space Space = isl::space::params_alloc(getIslCtx(), ParameterIds.size());
|
||||
|
||||
unsigned PDim = 0;
|
||||
for (const SCEV *Parameter : Parameters) {
|
||||
|
@ -1913,9 +1834,6 @@ isl::space Scop::getFullParamSpace() const {
|
|||
Space = Space.set_dim_id(isl::dim::param, PDim++, Id);
|
||||
}
|
||||
|
||||
for (isl::id Id : FortranIDs)
|
||||
Space = Space.set_dim_id(isl::dim::param, PDim++, Id);
|
||||
|
||||
return Space;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ add_llvm_pass_plugin(Polly
|
|||
Transform/ZoneAlgo.cpp
|
||||
Transform/Simplify.cpp
|
||||
Transform/MaximalStaticExpansion.cpp
|
||||
Transform/RewriteByReferenceParameters.cpp
|
||||
Transform/ScopInliner.cpp
|
||||
Transform/ManualOptimizer.cpp
|
||||
Transform/MatmulOptimizer.cpp
|
||||
|
|
|
@ -1160,84 +1160,6 @@ bool IslNodeBuilder::materializeParameters() {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Generate the computation of the size of the outermost dimension from the
|
||||
/// Fortran array descriptor (in this case, `@g_arr`). The final `%size`
|
||||
/// contains the size of the array.
|
||||
///
|
||||
/// %arrty = type { i8*, i64, i64, [3 x %desc.dimensionty] }
|
||||
/// %desc.dimensionty = type { i64, i64, i64 }
|
||||
/// @g_arr = global %arrty zeroinitializer, align 32
|
||||
/// ...
|
||||
/// %0 = load i64, i64* getelementptr inbounds
|
||||
/// (%arrty, %arrty* @g_arr, i64 0, i32 3, i64 0, i32 2)
|
||||
/// %1 = load i64, i64* getelementptr inbounds
|
||||
/// (%arrty, %arrty* @g_arr, i64 0, i32 3, i64 0, i32 1)
|
||||
/// %2 = sub nsw i64 %0, %1
|
||||
/// %size = add nsw i64 %2, 1
|
||||
static Value *buildFADOutermostDimensionLoad(Value *GlobalDescriptor,
|
||||
PollyIRBuilder &Builder,
|
||||
std::string ArrayName) {
|
||||
assert(GlobalDescriptor && "invalid global descriptor given");
|
||||
Type *Ty = GlobalDescriptor->getType()->getPointerElementType();
|
||||
|
||||
Value *endIdx[4] = {Builder.getInt64(0), Builder.getInt32(3),
|
||||
Builder.getInt64(0), Builder.getInt32(2)};
|
||||
Value *endPtr = Builder.CreateInBoundsGEP(Ty, GlobalDescriptor, endIdx,
|
||||
ArrayName + "_end_ptr");
|
||||
Type *type = cast<GEPOperator>(endPtr)->getResultElementType();
|
||||
assert(isa<IntegerType>(type) && "expected type of end to be integral");
|
||||
|
||||
Value *end = Builder.CreateLoad(type, endPtr, ArrayName + "_end");
|
||||
|
||||
Value *beginIdx[4] = {Builder.getInt64(0), Builder.getInt32(3),
|
||||
Builder.getInt64(0), Builder.getInt32(1)};
|
||||
Value *beginPtr = Builder.CreateInBoundsGEP(Ty, GlobalDescriptor, beginIdx,
|
||||
ArrayName + "_begin_ptr");
|
||||
Value *begin = Builder.CreateLoad(type, beginPtr, ArrayName + "_begin");
|
||||
|
||||
Value *size =
|
||||
Builder.CreateNSWSub(end, begin, ArrayName + "_end_begin_delta");
|
||||
|
||||
size = Builder.CreateNSWAdd(
|
||||
end, ConstantInt::get(type, 1, /* signed = */ true), ArrayName + "_size");
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool IslNodeBuilder::materializeFortranArrayOutermostDimension() {
|
||||
for (ScopArrayInfo *Array : S.arrays()) {
|
||||
if (Array->getNumberOfDimensions() == 0)
|
||||
continue;
|
||||
|
||||
Value *FAD = Array->getFortranArrayDescriptor();
|
||||
if (!FAD)
|
||||
continue;
|
||||
|
||||
isl_pw_aff *ParametricPwAff = Array->getDimensionSizePw(0).release();
|
||||
assert(ParametricPwAff && "parametric pw_aff corresponding "
|
||||
"to outermost dimension does not "
|
||||
"exist");
|
||||
|
||||
isl_id *Id = isl_pw_aff_get_dim_id(ParametricPwAff, isl_dim_param, 0);
|
||||
isl_pw_aff_free(ParametricPwAff);
|
||||
|
||||
assert(Id && "pw_aff is not parametric");
|
||||
|
||||
if (IDToValue.count(Id)) {
|
||||
isl_id_free(Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
Value *FinalValue =
|
||||
buildFADOutermostDimensionLoad(FAD, Builder, Array->getName());
|
||||
assert(FinalValue && "unable to build Fortran array "
|
||||
"descriptor load of outermost dimension");
|
||||
IDToValue[Id] = FinalValue;
|
||||
isl_id_free(Id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Value *IslNodeBuilder::preloadUnconditionally(isl_set *AccessRange,
|
||||
isl_ast_build *Build,
|
||||
Instruction *AccInst) {
|
||||
|
@ -1569,12 +1491,6 @@ void IslNodeBuilder::addParameters(__isl_take isl_set *Context) {
|
|||
// Materialize values for the parameters of the SCoP.
|
||||
materializeParameters();
|
||||
|
||||
// materialize the outermost dimension parameters for a Fortran array.
|
||||
// NOTE: materializeParameters() does not work since it looks through
|
||||
// the SCEVs. We don't have a corresponding SCEV for the array size
|
||||
// parameter
|
||||
materializeFortranArrayOutermostDimension();
|
||||
|
||||
// Generate values for the current loop iteration for all surrounding loops.
|
||||
//
|
||||
// We may also reference loops outside of the scop which do not contain the
|
||||
|
|
|
@ -264,7 +264,6 @@ void initializePollyPasses(PassRegistry &Registry) {
|
|||
initializeScopInlinerPass(Registry);
|
||||
initializeScopInfoRegionPassPass(Registry);
|
||||
initializeScopInfoWrapperPassPass(Registry);
|
||||
initializeRewriteByrefParamsWrapperPassPass(Registry);
|
||||
initializeCodegenCleanupPass(Registry);
|
||||
initializeFlattenSchedulePass(Registry);
|
||||
initializeForwardOpTreeWrapperPassPass(Registry);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "polly/Canonicalization.h"
|
||||
#include "polly/LinkAllPasses.h"
|
||||
#include "polly/Options.h"
|
||||
#include "polly/RewriteByReferenceParameters.h"
|
||||
#include "llvm/Analysis/GlobalsModRef.h"
|
||||
#include "llvm/Analysis/ProfileSummaryInfo.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
|
@ -42,7 +41,6 @@ static cl::opt<bool>
|
|||
|
||||
void polly::registerCanonicalicationPasses(llvm::legacy::PassManagerBase &PM) {
|
||||
bool UseMemSSA = true;
|
||||
PM.add(polly::createRewriteByrefParamsWrapperPass());
|
||||
PM.add(llvm::createPromoteMemoryToRegisterPass());
|
||||
PM.add(llvm::createEarlyCSEPass(UseMemSSA));
|
||||
PM.add(llvm::createInstructionCombiningPass());
|
||||
|
@ -98,7 +96,6 @@ polly::buildCanonicalicationPassesForNPM(llvm::ModulePassManager &MPM,
|
|||
FunctionPassManager FPM;
|
||||
|
||||
bool UseMemSSA = true;
|
||||
FPM.addPass(RewriteByrefParamsPass());
|
||||
FPM.addPass(PromotePass());
|
||||
FPM.addPass(EarlyCSEPass(UseMemSSA));
|
||||
FPM.addPass(InstCombinePass());
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
//===------ RewriteByReferenceParameters.cpp --------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass introduces separate 'alloca' instructions for read-only
|
||||
// by-reference function parameters to indicate that these paramters are
|
||||
// read-only. After this transformation -mem2reg has more freedom to promote
|
||||
// variables to registers, which allows SCEV to work in more cases.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "polly/RewriteByReferenceParameters.h"
|
||||
#include "polly/LinkAllPasses.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
#define DEBUG_TYPE "polly-rewrite-byref-params"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
static void tryRewriteInstruction(Instruction &Inst) {
|
||||
BasicBlock *Entry = &Inst.getParent()->getParent()->getEntryBlock();
|
||||
|
||||
auto *Call = dyn_cast<CallInst>(&Inst);
|
||||
|
||||
if (!Call)
|
||||
return;
|
||||
|
||||
llvm::Function *F = Call->getCalledFunction();
|
||||
|
||||
if (!F)
|
||||
return;
|
||||
|
||||
// We currently match for a very specific function. In case this proves
|
||||
// useful, we can make this code dependent on readonly metadata.
|
||||
if (!F->hasName() || F->getName() != "_gfortran_transfer_integer_write")
|
||||
return;
|
||||
|
||||
auto *BitCast = dyn_cast<BitCastInst>(Call->getOperand(1));
|
||||
|
||||
if (!BitCast)
|
||||
return;
|
||||
|
||||
auto *Alloca = dyn_cast<AllocaInst>(BitCast->getOperand(0));
|
||||
|
||||
if (!Alloca)
|
||||
return;
|
||||
|
||||
std::string InstName = Alloca->getName().str();
|
||||
|
||||
auto NewAlloca =
|
||||
new AllocaInst(Alloca->getAllocatedType(), 0,
|
||||
"polly_byref_alloca_" + InstName, &*Entry->begin());
|
||||
|
||||
auto *LoadedVal = new LoadInst(Alloca->getAllocatedType(), Alloca,
|
||||
"polly_byref_load_" + InstName, &Inst);
|
||||
|
||||
new StoreInst(LoadedVal, NewAlloca, &Inst);
|
||||
auto *NewBitCast = new BitCastInst(NewAlloca, BitCast->getType(),
|
||||
"polly_byref_cast_" + InstName, &Inst);
|
||||
Call->setOperand(1, NewBitCast);
|
||||
}
|
||||
|
||||
static void runRewriteByrefParams(Function &F) {
|
||||
for (BasicBlock &BB : F)
|
||||
for (Instruction &Inst : BB)
|
||||
tryRewriteInstruction(Inst);
|
||||
}
|
||||
|
||||
class RewriteByrefParamsWrapperPass : public FunctionPass {
|
||||
private:
|
||||
RewriteByrefParamsWrapperPass(const RewriteByrefParamsWrapperPass &) = delete;
|
||||
const RewriteByrefParamsWrapperPass &
|
||||
operator=(const RewriteByrefParamsWrapperPass &) = delete;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
explicit RewriteByrefParamsWrapperPass() : FunctionPass(ID) {}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const override {}
|
||||
|
||||
virtual bool runOnFunction(Function &F) override {
|
||||
runRewriteByrefParams(F);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
char RewriteByrefParamsWrapperPass::ID;
|
||||
} // anonymous namespace
|
||||
|
||||
Pass *polly::createRewriteByrefParamsWrapperPass() {
|
||||
return new RewriteByrefParamsWrapperPass();
|
||||
}
|
||||
|
||||
llvm::PreservedAnalyses
|
||||
polly ::RewriteByrefParamsPass::run(llvm::Function &F,
|
||||
llvm::FunctionAnalysisManager &FAM) {
|
||||
runRewriteByrefParams(F);
|
||||
return PreservedAnalyses::none();
|
||||
}
|
||||
|
||||
INITIALIZE_PASS_BEGIN(RewriteByrefParamsWrapperPass,
|
||||
"polly-rewrite-byref-params",
|
||||
"Polly - Rewrite by reference parameters", false, false)
|
||||
INITIALIZE_PASS_END(RewriteByrefParamsWrapperPass, "polly-rewrite-byref-params",
|
||||
"Polly - Rewrite by reference parameters", false, false)
|
|
@ -1,77 +0,0 @@
|
|||
; Check that the runtime size computation is generated for Fortran arrays.
|
||||
|
||||
; Regular code generation backend:
|
||||
; RUN: opt %loadPolly -S -polly-detect-fortran-arrays \
|
||||
; RUN: -polly-codegen < %s | FileCheck %s
|
||||
|
||||
; What the input fortran code should look like. NOTE: this is fake, the
|
||||
; .ll file was hand-written.
|
||||
;
|
||||
; MODULE testmod
|
||||
; USE data_parameters, ONLY : &
|
||||
; IMPLICIT NONE
|
||||
;
|
||||
; INTEGER (KIND=iintegers), ALLOCATABLE, PRIVATE :: &
|
||||
; arrin(:), arrout(:)
|
||||
; CONTAINS
|
||||
;
|
||||
; SUBROUTINE test()
|
||||
; INTEGER (KIND=iintegers) :: i
|
||||
;
|
||||
; DO i = 1, 100
|
||||
; arrout(i) = arrin(i) * arrin(i)
|
||||
; END DO
|
||||
; END SUBROUTINE test
|
||||
; END MODULE testmod
|
||||
|
||||
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i32:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
|
||||
|
||||
%"struct.array1_real(kind=8)" = type { i8*, i32, i32, [1 x %struct.descriptor_dimension] }
|
||||
%struct.descriptor_dimension = type { i32, i32, i32 }
|
||||
|
||||
@arrin = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32
|
||||
@arrout = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @__src_soil_MOD_terra1() unnamed_addr #0 {
|
||||
entry:
|
||||
br label %entry.split
|
||||
|
||||
entry.split: ; preds = %entry
|
||||
%rawmemin1 = load i32*, i32** bitcast (%"struct.array1_real(kind=8)"* @arrin to i32**), align 32, !tbaa !0
|
||||
%rawmemout2 = load i32*, i32** bitcast (%"struct.array1_real(kind=8)"* @arrout to i32**), align 32, !tbaa !0
|
||||
br label %for.body
|
||||
|
||||
for.body: ; preds = %entry.split, %for.body
|
||||
%indvars.iv = phi i64 [ 1, %entry.split ], [ %indvars.iv.next4, %for.body ]
|
||||
%inslot = getelementptr inbounds i32, i32* %rawmemin1, i64 %indvars.iv
|
||||
%inval = load i32, i32* %inslot, align 8
|
||||
%outslot = getelementptr inbounds i32, i32* %rawmemout2, i64 %indvars.iv
|
||||
%out = mul nsw i32 %inval, %inval
|
||||
store i32 %out, i32* %outslot, align 8
|
||||
%indvars.iv.next4 = add nuw nsw i64 %indvars.iv, 1
|
||||
%exitcond = icmp eq i64 %indvars.iv.next4, 100
|
||||
br i1 %exitcond, label %return, label %for.body
|
||||
|
||||
return: ; preds = %for.body
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind uwtable }
|
||||
|
||||
!0 = !{!1, !1, i32 0}
|
||||
!1 = !{!"alias set 3: void*", !2}
|
||||
!2 = distinct !{!2}
|
||||
|
||||
|
||||
; CHECK: %MemRef_rawmemin1_end = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrin, i64 0, i32 3, i64 0, i32 2)
|
||||
; CHECK-NEXT: %MemRef_rawmemin1_begin = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrin, i64 0, i32 3, i64 0, i32 1)
|
||||
; CHECK-NEXT: %MemRef_rawmemin1_end_begin_delta = sub nsw i32 %MemRef_rawmemin1_end, %MemRef_rawmemin1_begin
|
||||
; CHECK-NEXT: %MemRef_rawmemin1_size = add nsw i32 %MemRef_rawmemin1_end, 1
|
||||
; CHECK-NEXT: %MemRef_rawmemout2_end = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrout, i64 0, i32 3, i64 0, i32 2)
|
||||
; CHECK-NEXT: %MemRef_rawmemout2_begin = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrout, i64 0, i32 3, i64 0, i32 1)
|
||||
; CHECK-NEXT: %MemRef_rawmemout2_end_begin_delta = sub nsw i32 %MemRef_rawmemout2_end, %MemRef_rawmemout2_begin
|
||||
; CHECK-NEXT: %MemRef_rawmemout2_size = add nsw i32 %MemRef_rawmemout2_end, 1
|
|
@ -1,103 +0,0 @@
|
|||
; RUN: opt %loadPolly -analyze -polly-scops \
|
||||
; RUN: -polly-detect-fortran-arrays \
|
||||
; RUN: -polly-invariant-load-hoisting \
|
||||
; RUN: -polly-use-llvm-names \
|
||||
; RUN: -polly-stmt-granularity=bb \
|
||||
; RUN: < %s | FileCheck %s --check-prefix=SCOP
|
||||
|
||||
; RUN: opt %loadPolly -S \
|
||||
; RUN: -polly-detect-fortran-arrays \
|
||||
; RUN: -polly-codegen-ppcg \
|
||||
; RUN: -polly-invariant-load-hoisting \
|
||||
; RUN: -polly-use-llvm-names \
|
||||
; RUN: -polly-acc-fail-on-verify-module-failure \
|
||||
; RUN: < %s | FileCheck %s --check-prefix=HOST-IR
|
||||
|
||||
; REQUIRES: pollyacc
|
||||
|
||||
; In Polly, we specifically add a parameter to represent the outermost dimension
|
||||
; size of fortran arrays. We do this because this information is statically
|
||||
; available from the fortran metadata generated by dragonegg.
|
||||
; However, we were only materializing these parameters (meaning, creating an
|
||||
; llvm::Value to back the isl_id) from *memory accesses*. This is wrong,
|
||||
; we should materialize parameters from *scop array info*.
|
||||
|
||||
; It is wrong because if there is a case where we detect 2 fortran arrays,
|
||||
; but only one of them is accessed, we may not materialize the other array's
|
||||
; dimensions at all.
|
||||
|
||||
; This test case checks that we do not fail if there is an array that does
|
||||
; not have an access (In this case, `memory`), we still generate the
|
||||
; parameter.
|
||||
|
||||
; Check that we detect the function as a Scop.
|
||||
; SCOP: Function: f
|
||||
; SCOP-NEXT: Region: %loop.prepare---%for.exit
|
||||
; SCOP-NEXT: Max Loop Depth: 1
|
||||
|
||||
; Check that we detect fortran arrays.
|
||||
; SCOP: Arrays (Bounds as pw_affs) {
|
||||
; SCOP: double* MemRef_global_arr[*]; // Element size 8
|
||||
; SCOP-NEXT: double MemRef_memory[ [MemRef_memory_fortranarr_size] -> { [] -> [(MemRef_memory_fortranarr_size)] } ]; [BasePtrOrigin: MemRef_global_arr] // Element size 8
|
||||
; SCOP-NEXT: double MemRef_memory2[ [MemRef_memory2_fortranarr_size] -> { [] -> [(MemRef_memory2_fortranarr_size)] } ]; [BasePtrOrigin: MemRef_global_arr] // Element size 8
|
||||
; SCOP-NEXT: }
|
||||
|
||||
; Check that we have writes *only* into memory2, not into memory.
|
||||
; SCOP: Statements {
|
||||
; SCOP: Stmt_for_body
|
||||
; SCOP: MustWriteAccess := [Reduction Type: NONE] [Fortran array descriptor: global_arr] [Scalar: 0]
|
||||
; SCOP-NEXT: [start_val, end_val, offset, MemRef_memory_fortranarr_size, MemRef_memory2_fortranarr_size] -> { Stmt_for_body[i0] -> MemRef_memory2[start_val + offset + i0] };
|
||||
; SCOP-NEXT: ReadAccess := [Reduction Type: NONE] [Fortran array descriptor: global_arr] [Scalar: 0]
|
||||
; SCOP-NEXT: [start_val, end_val, offset, MemRef_memory_fortranarr_size, MemRef_memory2_fortranarr_size] -> { Stmt_for_body[i0] -> MemRef_memory2[start_val + offset + i0] };
|
||||
; SCOP-NEXT: }
|
||||
|
||||
; Check that we materialize the sizes and send it across to the kernel.
|
||||
; HOST-IR: store i64 %MemRef_memory_size, i64* %polly_launch_0_param_4
|
||||
; HOST-IR: store i64 %MemRef_memory2_size, i64* %polly_launch_0_param_5
|
||||
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
|
||||
|
||||
%"struct.array1_real(kind=8)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
%struct.descriptor_dimension = type { i64, i64, i64 }
|
||||
|
||||
@global_arr = external unnamed_addr global %"struct.array1_real(kind=8)", align 32
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @f(i32* noalias %ipstart, i32* noalias %ipend) unnamed_addr #0 {
|
||||
entry:
|
||||
br label %loop.prepare
|
||||
|
||||
|
||||
loop.prepare: ; preds = %"6", %"3.preheader"
|
||||
%start.val = load i32, i32* %ipstart, align 4
|
||||
%end.val = load i32, i32* %ipend, align 4
|
||||
%should.loop = icmp sgt i32 %start.val, %end.val
|
||||
br i1 %should.loop, label %for.exit, label %for.body
|
||||
|
||||
|
||||
for.body: ; preds = %for.body, %"4.preheader"
|
||||
%i = phi i32 [ %i.next, %for.body ], [ %start.val, %loop.prepare ]
|
||||
%i.sext = sext i32 %i to i64
|
||||
%memory = load double*, double** bitcast (%"struct.array1_real(kind=8)"* @global_arr to double**), align 32
|
||||
%offset = load i64, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @global_arr, i64 0, i32 1), align 8
|
||||
%idx = add i64 %offset, %i.sext
|
||||
%slot = getelementptr double, double* %memory, i64 %idx
|
||||
store double 1.0, double* %slot, align 8
|
||||
|
||||
%memory2 = load double*, double** bitcast (%"struct.array1_real(kind=8)"* @global_arr to double**), align 32
|
||||
%offset2 = load i64, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @global_arr, i64 0, i32 1), align 8
|
||||
%idx2 = add i64 %offset2, %i.sext
|
||||
%slot2 = getelementptr double, double* %memory2, i64 %idx2
|
||||
%val = load double, double* %slot2, align 8
|
||||
|
||||
%should.loopexit = icmp eq i32 %i, %end.val
|
||||
%i.next = add i32 %i, 1
|
||||
br i1 %should.loopexit, label %for.exit, label %for.body
|
||||
|
||||
for.exit: ; preds = %for.body
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind uwtable }
|
|
@ -1,40 +0,0 @@
|
|||
; RUN: opt %loadPolly -polly-rewrite-byref-params -S < %s \
|
||||
; RUN: | FileCheck %s
|
||||
|
||||
|
||||
; Verify that we rewrite the read-only by-reference into a separate alloca slot.
|
||||
; This is useful in case %j3 is an induction variable, which should be promoted
|
||||
; by -mem2reg into a register.
|
||||
|
||||
; CHECK: define void @foo(%struct.__st_parameter_dt* %p) {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: %polly_byref_alloca_j3 = alloca i32
|
||||
; CHECK-NEXT: %j3 = alloca i32, align 4
|
||||
; CHECK-NEXT: %tmp = bitcast i32* %j3 to i8*
|
||||
; CHECK-NEXT: br label %bb
|
||||
|
||||
; CHECK: bb: ; preds = %entry
|
||||
; CHECK-NEXT: %polly_byref_load_j3 = load i32, i32* %j3
|
||||
; CHECK-NEXT: store i32 %polly_byref_load_j3, i32* %polly_byref_alloca_j3
|
||||
; CHECK-NEXT: %polly_byref_cast_j3 = bitcast i32* %polly_byref_alloca_j3 to i8*
|
||||
; CHECK-NEXT: call void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt* %p, i8* %polly_byref_cast_j3, i32 4)
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK-NEXT: }
|
||||
|
||||
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
%struct.__st_parameter_dt = type { }
|
||||
|
||||
declare void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt*, i8*, i32)
|
||||
|
||||
define void @foo(%struct.__st_parameter_dt* %p) {
|
||||
entry:
|
||||
%j3 = alloca i32, align 4
|
||||
%tmp = bitcast i32* %j3 to i8*
|
||||
br label %bb
|
||||
|
||||
bb:
|
||||
call void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt* %p, i8* %tmp, i32 4)
|
||||
ret void
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
; RUN: opt %loadPolly -analyze -S -polly-detect-fortran-arrays \
|
||||
; RUN: -polly-process-unprofitable -polly-scops < %s | FileCheck %s
|
||||
|
||||
; MODULE src_soil
|
||||
; USE data_parameters, ONLY : &
|
||||
; wp, & ! KIND-type parameter for real variables
|
||||
; iintegers ! KIND-type parameter for standard integer variables
|
||||
; IMPLICIT NONE
|
||||
; REAL (KIND = wp), ALLOCATABLE, PRIVATE :: &
|
||||
; xdzs (:)
|
||||
; CONTAINS
|
||||
; SUBROUTINE terra1(n)
|
||||
; INTEGER, intent(in) :: n
|
||||
; INTEGER (KIND=iintegers) :: &
|
||||
; j
|
||||
; Allocate(xdzs(n));
|
||||
; DO j = 2, n
|
||||
; xdzs(j) = xdzs(j) * xdzs(j) + xdzs(j - 1)
|
||||
; END DO
|
||||
; END SUBROUTINE terra1
|
||||
; END MODULE src_soil
|
||||
|
||||
|
||||
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
|
||||
|
||||
%"struct.array1_real(kind=8)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
%struct.descriptor_dimension = type { i64, i64, i64 }
|
||||
|
||||
@__src_soil_MOD_xdzs = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32
|
||||
@.cst = private unnamed_addr constant [67 x i8] c"Integer overflow when calculating the amount of memory to allocate\00", align 64
|
||||
@.cst1 = private unnamed_addr constant [37 x i8] c"Allocation would exceed memory limit\00", align 64
|
||||
@.cst2 = private unnamed_addr constant [93 x i8] c"At line 23 of file /home/siddhart/cosmo-self-installation/cosmo-pompa/cosmo/src/src_soil.f90\00", align 64
|
||||
@.cst3 = private unnamed_addr constant [55 x i8] c"Attempting to allocate already allocated variable '%s'\00", align 64
|
||||
@.cst4 = private unnamed_addr constant [5 x i8] c"xdzs\00", align 8
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @__src_soil_MOD_terra1(i32* noalias nocapture %n) unnamed_addr #0 {
|
||||
entry:
|
||||
br label %entry.split
|
||||
|
||||
entry.split: ; preds = %entry
|
||||
store i64 537, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 2), align 16, !tbaa !0
|
||||
store i64 1, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 3, i64 0, i32 1), align 8, !tbaa !0
|
||||
%tmp = load i32, i32* %n, align 4, !tbaa !3
|
||||
%tmp1 = sext i32 %tmp to i64
|
||||
store i64 %tmp1, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 3, i64 0, i32 2), align 8, !tbaa !0
|
||||
store i64 1, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 3, i64 0, i32 0), align 8, !tbaa !0
|
||||
%tmp2 = icmp slt i32 %tmp, 1
|
||||
%tmp3 = zext i32 %tmp to i64
|
||||
%tmp4 = shl nuw nsw i64 %tmp3, 3
|
||||
%.24 = select i1 %tmp2, i64 0, i64 %tmp4
|
||||
%tmp5 = icmp ne i64 %.24, 0
|
||||
%tmp6 = select i1 %tmp5, i64 %.24, i64 1
|
||||
%tmp7 = tail call noalias i8* @malloc(i64 %tmp6) #2
|
||||
store i8* %tmp7, i8** getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 0), align 32, !tbaa !5
|
||||
store i64 -1, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 1), align 8, !tbaa !0
|
||||
%tmp8 = icmp sgt i32 %tmp, 1
|
||||
br i1 %tmp8, label %"21.preheader", label %return
|
||||
|
||||
"21.preheader": ; preds = %entry.split
|
||||
%tmp9 = bitcast i8* %tmp7 to double*
|
||||
%tmp10 = add i32 %tmp, 1
|
||||
br label %"21"
|
||||
|
||||
"21": ; preds = %"21", %"21.preheader"
|
||||
%tmp11 = phi double [ undef, %"21.preheader" ], [ %tmp16, %"21" ]
|
||||
%indvars.iv = phi i64 [ 2, %"21.preheader" ], [ %indvars.iv.next, %"21" ]
|
||||
%tmp12 = add nsw i64 %indvars.iv, -1
|
||||
%tmp13 = getelementptr inbounds double, double* %tmp9, i64 %tmp12
|
||||
%tmp14 = load double, double* %tmp13, align 8, !tbaa !7
|
||||
%tmp15 = fmul double %tmp14, %tmp14
|
||||
%tmp16 = fadd double %tmp11, %tmp15
|
||||
store double %tmp16, double* %tmp13, align 8, !tbaa !7
|
||||
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
|
||||
%lftr.wideiv1 = trunc i64 %indvars.iv.next to i32
|
||||
%exitcond2 = icmp eq i32 %lftr.wideiv1, %tmp10
|
||||
br i1 %exitcond2, label %return.loopexit, label %"21"
|
||||
|
||||
return.loopexit: ; preds = %"21"
|
||||
br label %return
|
||||
|
||||
return: ; preds = %return.loopexit, %entry.split
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: noreturn
|
||||
declare void @_gfortran_runtime_error(i8*, ...) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare noalias i8* @malloc(i64) #2
|
||||
|
||||
; Function Attrs: noreturn
|
||||
declare void @_gfortran_os_error(i8*) #1
|
||||
|
||||
; Function Attrs: noreturn
|
||||
declare void @_gfortran_runtime_error_at(i8*, i8*, ...) #1
|
||||
|
||||
attributes #0 = { nounwind uwtable }
|
||||
attributes #1 = { noreturn }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
!0 = !{!1, !1, i64 0}
|
||||
!1 = !{!"alias set 4: integer(kind=8)", !2}
|
||||
!2 = distinct !{!2}
|
||||
!3 = !{!4, !4, i64 0}
|
||||
!4 = !{!"alias set 11: integer(kind=4)", !2}
|
||||
!5 = !{!6, !6, i64 0}
|
||||
!6 = !{!"alias set 3: void*", !2}
|
||||
!7 = !{!8, !8, i64 0}
|
||||
!8 = !{!"alias set 18: real(kind=8)", !2}
|
||||
|
||||
; CHECK: ReadAccess := [Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
|
||||
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
|
|
@ -1,89 +0,0 @@
|
|||
; RUN: opt %loadPolly -analyze -S -polly-detect-fortran-arrays \
|
||||
; RUN: -polly-process-unprofitable -polly-scops < %s | FileCheck %s
|
||||
|
||||
; MODULE src_soil
|
||||
; USE data_parameters, ONLY : &
|
||||
; wp, & ! KIND-type parameter for real variables
|
||||
; iintegers ! KIND-type parameter for standard integer variables
|
||||
; IMPLICIT NONE
|
||||
; REAL (KIND = wp), ALLOCATABLE, PRIVATE :: &
|
||||
; xdzs (:)
|
||||
; CONTAINS
|
||||
;
|
||||
; SUBROUTINE terra1(n)
|
||||
; INTEGER, intent(in) :: n
|
||||
;
|
||||
; INTEGER (KIND=iintegers) :: &
|
||||
; j
|
||||
;
|
||||
; DO j = 22, n
|
||||
; xdzs(j) = xdzs(j) * xdzs(j) + xdzs(j - 1)
|
||||
; END DO
|
||||
; END SUBROUTINE terra1
|
||||
; END MODULE src_soil
|
||||
|
||||
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
|
||||
|
||||
%"struct.array1_real(kind=8)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
%struct.descriptor_dimension = type { i64, i64, i64 }
|
||||
|
||||
@__src_soil_MOD_xdzs = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @__src_soil_MOD_terra1(i32* noalias nocapture %n) unnamed_addr #0 {
|
||||
entry:
|
||||
br label %entry.split
|
||||
|
||||
entry.split: ; preds = %entry
|
||||
%tmp = load i32, i32* %n, align 4, !tbaa !0
|
||||
%tmp1 = icmp sgt i32 %tmp, 21
|
||||
br i1 %tmp1, label %"3.preheader", label %return
|
||||
|
||||
"3.preheader": ; preds = %entry.split
|
||||
%tmp2 = load i64, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 1), align 8, !tbaa !3
|
||||
%tmp3 = load double*, double** bitcast (%"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs to double**), align 32, !tbaa !5
|
||||
%tmp4 = add i32 %tmp, 1
|
||||
br label %"3"
|
||||
|
||||
"3": ; preds = %"3", %"3.preheader"
|
||||
%indvars.iv = phi i64 [ 22, %"3.preheader" ], [ %indvars.iv.next, %"3" ]
|
||||
%tmp5 = add nsw i64 %indvars.iv, %tmp2
|
||||
%tmp6 = getelementptr inbounds double, double* %tmp3, i64 %tmp5
|
||||
%tmp7 = load double, double* %tmp6, align 8, !tbaa !7
|
||||
%tmp8 = fmul double %tmp7, %tmp7
|
||||
%tmp9 = add i64 %tmp2, -1
|
||||
%tmp10 = add i64 %tmp9, %indvars.iv
|
||||
%tmp11 = getelementptr inbounds double, double* %tmp3, i64 %tmp10
|
||||
%tmp12 = load double, double* %tmp11, align 8, !tbaa !7
|
||||
%tmp13 = fadd double %tmp8, %tmp12
|
||||
store double %tmp13, double* %tmp6, align 8, !tbaa !7
|
||||
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
|
||||
%lftr.wideiv1 = trunc i64 %indvars.iv.next to i32
|
||||
%exitcond2 = icmp eq i32 %lftr.wideiv1, %tmp4
|
||||
br i1 %exitcond2, label %return.loopexit, label %"3"
|
||||
|
||||
return.loopexit: ; preds = %"3"
|
||||
br label %return
|
||||
|
||||
return: ; preds = %return.loopexit, %entry.split
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind uwtable }
|
||||
|
||||
!0 = !{!1, !1, i64 0}
|
||||
!1 = !{!"alias set 11: integer(kind=4)", !2}
|
||||
!2 = distinct !{!2}
|
||||
!3 = !{!4, !4, i64 0}
|
||||
!4 = !{!"alias set 4: integer(kind=8)", !2}
|
||||
!5 = !{!6, !6, i64 0}
|
||||
!6 = !{!"alias set 3: void*", !2}
|
||||
!7 = !{!8, !8, i64 0}
|
||||
!8 = !{!"alias set 18: real(kind=8)", !2}
|
||||
|
||||
; CHECK: ReadAccess := [Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
|
||||
; CHECK: ReadAccess := [Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
|
||||
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
|
|
@ -1,68 +0,0 @@
|
|||
; RUN: opt %loadPolly -analyze -polly-detect-fortran-arrays \
|
||||
; RUN: -polly-scops -polly-allow-nonaffine -polly-invariant-load-hoisting < %s | FileCheck %s
|
||||
|
||||
; This testcase is the corresponding LLVM for testfunc:
|
||||
; PROGRAM main
|
||||
; INTEGER, DIMENSION(1) :: xs
|
||||
;
|
||||
; CALL testfunc(xs, 10)
|
||||
; CONTAINS
|
||||
; SUBROUTINE func(xs, n)
|
||||
; IMPLICIT NONE
|
||||
; INTEGER, DIMENSION(:), INTENT(INOUT) :: xs
|
||||
; INTEGER, INTENT(IN) :: n
|
||||
; INTEGER :: i
|
||||
|
||||
; DO i = 1, n
|
||||
; xs(i) = 1
|
||||
; END DO
|
||||
;
|
||||
; END SUBROUTINE func
|
||||
; END PROGRAM
|
||||
|
||||
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
|
||||
|
||||
%"struct.array1_integer(kind=4)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
%struct.descriptor_dimension = type { i64, i64, i64 }
|
||||
|
||||
define internal void @testfunc(%"struct.array1_integer(kind=4)"* noalias %xs, i32* noalias %n) {
|
||||
entry:
|
||||
br label %entry.split
|
||||
|
||||
entry.split: ; preds = %entry
|
||||
%tmp = getelementptr inbounds %"struct.array1_integer(kind=4)", %"struct.array1_integer(kind=4)"* %xs, i64 0, i32 3, i64 0, i32 0
|
||||
%tmp1 = load i64, i64* %tmp, align 8
|
||||
%tmp2 = icmp eq i64 %tmp1, 0
|
||||
%tmp3 = select i1 %tmp2, i64 1, i64 %tmp1
|
||||
%tmp4 = bitcast %"struct.array1_integer(kind=4)"* %xs to i32**
|
||||
%tmp5 = load i32*, i32** %tmp4, align 8
|
||||
%tmp6 = load i32, i32* %n, align 4
|
||||
%tmp7 = icmp sgt i32 %tmp6, 0
|
||||
br i1 %tmp7, label %"6.preheader", label %return
|
||||
|
||||
"6.preheader": ; preds = %entry.split
|
||||
br label %"6"
|
||||
|
||||
"6": ; preds = %"6", %"6.preheader"
|
||||
%tmp8 = phi i32 [ %tmp14, %"6" ], [ 1, %"6.preheader" ]
|
||||
%tmp9 = sext i32 %tmp8 to i64
|
||||
%tmp10 = mul i64 %tmp3, %tmp9
|
||||
%tmp11 = sub i64 %tmp10, %tmp3
|
||||
%tmp12 = getelementptr i32, i32* %tmp5, i64 %tmp11
|
||||
; store
|
||||
store i32 1, i32* %tmp12, align 4
|
||||
%tmp13 = icmp eq i32 %tmp8, %tmp6
|
||||
%tmp14 = add i32 %tmp8, 1
|
||||
br i1 %tmp13, label %return.loopexit, label %"6"
|
||||
|
||||
return.loopexit: ; preds = %"6"
|
||||
br label %return
|
||||
|
||||
return: ; preds = %return.loopexit, %entry.split
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Fortran array descriptor: xs] [Scalar: 0]
|
|
@ -1,93 +0,0 @@
|
|||
; RUN: opt %loadPolly -analyze -polly-detect-fortran-arrays \
|
||||
; RUN: -polly-scops -polly-allow-nonaffine -polly-ignore-aliasing < %s | FileCheck %s
|
||||
|
||||
; PROGRAM main
|
||||
; ...
|
||||
; CONTAINS
|
||||
; SUBROUTINE copy(xs, ys, n)
|
||||
; IMPLICIT NONE
|
||||
; INTEGER, DIMENSION(:), INTENT(INOUT) :: xs, ys
|
||||
; INTEGER, INTENT(IN) :: n
|
||||
; INTEGER :: i
|
||||
;
|
||||
; DO i = 1, n
|
||||
; ys(i * i) = xs(i * i)
|
||||
; END DO
|
||||
;
|
||||
; END SUBROUTINE copy
|
||||
; END PROGRAM
|
||||
|
||||
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
|
||||
|
||||
%"struct.array1_integer(kind=4)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
%struct.descriptor_dimension = type { i64, i64, i64 }
|
||||
%"struct.array1_integer(kind=4).0" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
%"struct.array1_integer(kind=4).1" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
%"struct.array1_integer(kind=4).2" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
%struct.__st_parameter_dt = type { %struct.__st_parameter_common, i64, i64*, i64*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i8*, [256 x i8], i32*, i64, i8*, i32, i32, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i8*, i8*, i32, [4 x i8] }
|
||||
%struct.__st_parameter_common = type { i32, i32, i8*, i32, i32, i8*, i32* }
|
||||
%"struct.array1_integer(kind=4).3" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
|
||||
|
||||
@0 = internal constant i32 10
|
||||
@.cst = private constant [12 x i8] c"program.f90\00", align 8
|
||||
@options.12.1603 = internal constant [8 x i32] [i32 68, i32 511, i32 0, i32 0, i32 0, i32 1, i32 0, i32 1], align 32
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define internal void @copy.1550(%"struct.array1_integer(kind=4)"* noalias %xs, %"struct.array1_integer(kind=4).0"* noalias %ys, i32* noalias %n) {
|
||||
entry:
|
||||
br label %entry.split
|
||||
|
||||
entry.split: ; preds = %entry
|
||||
%0 = getelementptr inbounds %"struct.array1_integer(kind=4).0", %"struct.array1_integer(kind=4).0"* %ys, i64 0, i32 3, i64 0, i32 0
|
||||
%1 = load i64, i64* %0, align 8
|
||||
%2 = icmp eq i64 %1, 0
|
||||
%3 = select i1 %2, i64 1, i64 %1
|
||||
%4 = bitcast %"struct.array1_integer(kind=4).0"* %ys to i32**
|
||||
%5 = load i32*, i32** %4, align 8
|
||||
%6 = getelementptr inbounds %"struct.array1_integer(kind=4)", %"struct.array1_integer(kind=4)"* %xs, i64 0, i32 3, i64 0, i32 0
|
||||
%7 = load i64, i64* %6, align 8
|
||||
%8 = icmp eq i64 %7, 0
|
||||
%. = select i1 %8, i64 1, i64 %7
|
||||
%9 = bitcast %"struct.array1_integer(kind=4)"* %xs to i32**
|
||||
%10 = load i32*, i32** %9, align 8
|
||||
%11 = load i32, i32* %n, align 4
|
||||
%12 = icmp sgt i32 %11, 0
|
||||
br i1 %12, label %"9.preheader", label %return
|
||||
|
||||
"9.preheader": ; preds = %entry.split
|
||||
br label %"9"
|
||||
|
||||
"9": ; preds = %"9.preheader", %"9"
|
||||
%13 = phi i32 [ %26, %"9" ], [ 1, %"9.preheader" ]
|
||||
%14 = mul i32 %13, %13
|
||||
%15 = sext i32 %14 to i64
|
||||
%16 = mul i64 %3, %15
|
||||
%17 = sub i64 %16, %3
|
||||
%18 = mul i32 %13, %13
|
||||
%19 = sext i32 %18 to i64
|
||||
%20 = mul i64 %., %19
|
||||
%21 = sub i64 %20, %.
|
||||
%22 = getelementptr i32, i32* %10, i64 %21
|
||||
; load
|
||||
%23 = load i32, i32* %22, align 4
|
||||
%24 = getelementptr i32, i32* %5, i64 %17
|
||||
; write
|
||||
store i32 %23, i32* %24, align 4
|
||||
%25 = icmp eq i32 %13, %11
|
||||
%26 = add i32 %13, 1
|
||||
br i1 %25, label %return.loopexit, label %"9"
|
||||
|
||||
return.loopexit: ; preds = %"9"
|
||||
br label %return
|
||||
|
||||
return: ; preds = %return.loopexit, %entry.split
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: ReadAccess := [Reduction Type: NONE] [Fortran array descriptor: xs] [Scalar: 0]
|
||||
; CHECK-NEXT: [p_0_loaded_from_n, MemRef0_fortranarr_size, MemRef1_fortranarr_size] -> { Stmt_9[i0] -> MemRef0[o0] };
|
||||
; CHECK-NEXT: MayWriteAccess := [Reduction Type: NONE] [Fortran array descriptor: ys] [Scalar: 0]
|
||||
; CHECK-NEXT: [p_0_loaded_from_n, MemRef0_fortranarr_size, MemRef1_fortranarr_size] -> { Stmt_9[i0] -> MemRef1[o0] };
|
Loading…
Reference in a new issue