[polly] r303040 - [Fortran Support] Add pattern match for Fortran Arrays that are parameters.
Siddharth Bhat via llvm-commits
llvm-commits at lists.llvm.org
Mon May 15 01:41:30 PDT 2017
Author: bollu
Date: Mon May 15 03:41:30 2017
New Revision: 303040
URL: http://llvm.org/viewvc/llvm-project?rev=303040&view=rev
Log:
[Fortran Support] Add pattern match for Fortran Arrays that are parameters.
- This breaks the previous assumption that Fortran Arrays are `GlobalValue`.
- The names of functions were getting unwieldy. So, I renamed the
Fortran related functions.
Differential Revision: https://reviews.llvm.org/D33075
Added:
polly/trunk/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll
Modified:
polly/trunk/include/polly/ScopBuilder.h
polly/trunk/include/polly/ScopInfo.h
polly/trunk/lib/Analysis/ScopBuilder.cpp
polly/trunk/lib/Analysis/ScopInfo.cpp
Modified: polly/trunk/include/polly/ScopBuilder.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopBuilder.h?rev=303040&r1=303039&r2=303040&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopBuilder.h (original)
+++ polly/trunk/include/polly/ScopBuilder.h Mon May 15 03:41:30 2017
@@ -57,28 +57,75 @@ class ScopBuilder {
// Methods for pattern matching against Fortran code generated by dragonegg.
// @{
- /// Try to pattern match and find the array descriptor structure in case of a
- /// fortran array accesss. succeeds on load/store into a fortran array that
- /// has been allocated.
+ /// Try to match for the descriptor of a Fortran Array that has been declared
+ /// global, and is allocated in this module.
///
- /// @see polly::FortranArrayDescriptor
+ /// "@globaldescriptor" is the descriptor of the Fortran Array.
///
- /// @param Inst The load/store instruction that access the memory.
+ /// Pattern match for "@globaldescriptor":
+ /// 1. %mem = load double*, double** bitcast (%"struct.array1_real(kind=8)"*
+ /// @globaldescriptor 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, align 8
+ /// 3.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 @globaldescriptor on success, nullptr on failure.
+ Value *findFADGlobalAlloc(MemAccInst Inst);
+
+ /// Try to match for the descriptor of a Fortran Array that has been declared
+ /// global, and is being accessed across modules.
+ ///
+ /// Pattern match for "@globaldescriptor":
+ /// 1. %mem = load double*, double** bitcast (%"struct.array1_real(kind=8)"*
+ /// @globaldescriptor 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, align 8
+ /// 3.2 store/load <memtype> <val>, <memtype>* %mem, align 8
+ ///
+ /// @see polly::MemoryAccess, polly::ScopArrayInfo
///
/// @note assumes -polly-canonicalize has been run.
- GlobalValue *findFortranArrayDescriptorForAllocArrayAccess(MemAccInst Inst);
+ ///
+ /// @param Inst The LoadInst/StoreInst that accesses the memory.
+ ///
+ /// @returns Reference to @globaldescriptor on success, nullptr on failure.
+ Value *findFADGlobalNonAlloc(MemAccInst Inst);
- /// Try to pattern match and find the array descriptor structure in case of a
- /// fortran array accesss. succeeds on load/store into a fortran array that
- /// has been allocated.
+ /// Try to match for the descriptor of a Fortran array that is a parameter
+ /// to a function, and has not been allocated.
///
- /// @see polly::FortranArrayDescriptor
+ /// Pattern match for "%param":
+ /// 1. %mem = bitcast %"struct.array1_integer(kind=4)"* %param to i32**
///
- /// @param Inst The load/store instruction that access the memory.
+ /// 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, align 8
+ /// 3.2 store/load <memtype> <val>, <memtype>* %mem, align 8
+ ///
+ /// @see polly::MemoryAccess, polly::ScopArrayInfo
///
/// @note assumes -polly-canonicalize has been run.
- GlobalValue *
- findFortranArrayDescriptorForNonAllocArrayAccess(MemAccInst Inst);
+ ///
+ /// @param Inst The LoadInst/StoreInst that accesses the memory.
+ ///
+ /// @returns Reference to "%param" on success, nullptr on failure.
+ Value *findFADLocalNonAlloc(MemAccInst Inst);
// @}
// Build the SCoP for Region @p R.
Modified: polly/trunk/include/polly/ScopInfo.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopInfo.h?rev=303040&r1=303039&r2=303040&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopInfo.h (original)
+++ polly/trunk/include/polly/ScopInfo.h Mon May 15 03:41:30 2017
@@ -616,12 +616,12 @@ private:
/// Updated access relation read from JSCOP file.
isl_map *NewAccessRelation;
- /// Fortran arrays that are created using "Allocate" are stored in terms
+ /// 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<GlobalValue> FAD;
+ AssertingVH<Value> FAD;
// @}
__isl_give isl_basic_map *createBasicAccessMap(ScopStmt *Statement);
@@ -1020,7 +1020,7 @@ public:
/// Set the array descriptor corresponding to the Array on which the
/// memory access is performed.
- void setFortranArrayDescriptor(GlobalValue *FAD);
+ void setFortranArrayDescriptor(Value *FAD);
/// Update the original access relation.
///
Modified: polly/trunk/lib/Analysis/ScopBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopBuilder.cpp?rev=303040&r1=303039&r2=303040&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopBuilder.cpp (original)
+++ polly/trunk/lib/Analysis/ScopBuilder.cpp Mon May 15 03:41:30 2017
@@ -123,28 +123,36 @@ void ScopBuilder::buildEscapingDependenc
}
}
-/// Check that a global variable has a type resembling:
+/// 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> }
///
-/// @global = unnamed_addr global %"struct.array1_real(kind=8)"
-///
-/// This function checks that:
-/// 1. Global has a type name starting with "struct.array"
-/// 2. Global type has layout as shown
-/// 3. Final member of Global 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
+/// 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 arrays.
+/// generates for Fortran array descriptors.
+///
+/// @param V the Value to be checked.
///
-/// @param Global the global variable believed to be a Fortran array
-bool isGlobalFortranArray(GlobalValue *Global) {
- auto StructArrTy = dyn_cast<StructType>(Global->getValueType());
+/// @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;
@@ -158,7 +166,7 @@ bool isGlobalFortranArray(GlobalValue *G
const ArrayRef<Type *> ArrMemberTys = StructArrTy->elements();
// i8* match
- if (ArrMemberTys[0] != Type::getInt8PtrTy(Global->getContext()))
+ if (ArrMemberTys[0] != Type::getInt8PtrTy(V->getContext()))
return false;
// Get a reference to the int type and check that all the members
@@ -193,31 +201,7 @@ bool isGlobalFortranArray(GlobalValue *G
return true;
}
-/// This is matching against code generated by dragonegg after simplifier
-/// passes have been run.
-///
-/// This is trying to match against "@globaldescriptor", the descriptor
-/// of the Fortran array that is being accessed at load/store. This style
-/// of code is generated for arrays that have been allocated using "Allocate"
-/// in the same module.
-///
-/// Pattern Match:
-/// 1. %mallocmem = i8* @malloc(i64 40)
-///
-/// 5. store i8* %mallocmem, i8** getelementptr inbounds
-/// (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"*
-/// @globaldescriptor, i64 0, i32 0), align 32
-///
-/// 2. %typedmem = bitcast i8* %mallocmem 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>* %typedmem, align 8
-/// 4.2 store/load <memtype> <val>, <memtype>* %slot, align 8
-GlobalValue *
-ScopBuilder::findFortranArrayDescriptorForAllocArrayAccess(MemAccInst Inst) {
+Value *ScopBuilder::findFADGlobalNonAlloc(MemAccInst Inst) {
// match: 4.1 & 4.2 store/load
if (!isa<LoadInst>(Inst) && !isa<StoreInst>(Inst))
return nullptr;
@@ -274,13 +258,12 @@ ScopBuilder::findFortranArrayDescriptorF
if (!(DescriptorType && DescriptorType->hasName()))
continue;
- GlobalValue *Descriptor =
- dyn_cast<GlobalValue>(DescriptorGEP->getPointerOperand());
+ Value *Descriptor = dyn_cast<Value>(DescriptorGEP->getPointerOperand());
if (!Descriptor)
continue;
- if (!isGlobalFortranArray(Descriptor))
+ if (!isFortranArrayDescriptor(Descriptor))
continue;
return Descriptor;
@@ -289,26 +272,7 @@ ScopBuilder::findFortranArrayDescriptorF
return nullptr;
}
-/// This is matching against code generated by dragonegg after simplifier
-/// passes have been run.
-///
-/// This is trying to match against "@globaldescriptor", the descriptor
-/// of the Fortran array that is being accessed at load/store. This style
-/// of code is generated for arrays that have been declared global, and
-/// are being accessed across modules.
-///
-/// Pattern Match:
-/// 1. %mem = load double*, double** bitcast (%"struct.array1_real(kind=8)"*
-/// @globaldescriptor 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, align 8
-/// 3.2 store/load <memtype> <val>, <memtype>* %mem, align 8
-GlobalValue *
-ScopBuilder::findFortranArrayDescriptorForNonAllocArrayAccess(MemAccInst Inst) {
+Value *ScopBuilder::findFADGlobalAlloc(MemAccInst Inst) {
// match: 3
if (!isa<LoadInst>(Inst) && !isa<StoreInst>(Inst))
return nullptr;
@@ -337,12 +301,45 @@ ScopBuilder::findFortranArrayDescriptorF
if (!BitcastOperator)
return nullptr;
- GlobalValue *Descriptor =
- dyn_cast<GlobalValue>(BitcastOperator->getOperand(0));
+ Value *Descriptor = dyn_cast<Value>(BitcastOperator->getOperand(0));
+ if (!Descriptor)
+ return nullptr;
+
+ if (!isFortranArrayDescriptor(Descriptor))
+ return nullptr;
+
+ return Descriptor;
+}
+
+Value *ScopBuilder::findFADLocalNonAlloc(MemAccInst Inst) {
+ // match: 3
+ if (!isa<LoadInst>(Inst) && !isa<StoreInst>(Inst))
+ return nullptr;
+
+ // match: 3
+ if (Inst.getAlignment() != 8)
+ return nullptr;
+
+ Value *Slot = Inst.getPointerOperand();
+
+ BitCastOperator *MemBitcast = nullptr;
+ // [match: 2]
+ if (auto *SlotGEP = dyn_cast<GetElementPtrInst>(Slot)) {
+ // match: 1
+ MemBitcast = dyn_cast<BitCastOperator>(SlotGEP->getPointerOperand());
+ } else {
+ // match: 1
+ MemBitcast = dyn_cast<BitCastOperator>(Slot);
+ }
+
+ if (!MemBitcast)
+ return nullptr;
+
+ Value *Descriptor = dyn_cast<Value>(MemBitcast->getOperand(0));
if (!Descriptor)
return nullptr;
- if (!isGlobalFortranArray(Descriptor))
+ if (!isFortranArrayDescriptor(Descriptor))
return nullptr;
return Descriptor;
@@ -774,11 +771,11 @@ void ScopBuilder::addArrayAccess(
if (!DetectFortranArrays)
return;
- if (GlobalValue *FAD =
- findFortranArrayDescriptorForAllocArrayAccess(MemAccInst))
+ if (Value *FAD = findFADGlobalNonAlloc(MemAccInst))
+ MemAccess->setFortranArrayDescriptor(FAD);
+ else if (Value *FAD = findFADGlobalAlloc(MemAccInst))
MemAccess->setFortranArrayDescriptor(FAD);
- else if (GlobalValue *FAD =
- findFortranArrayDescriptorForNonAllocArrayAccess(MemAccInst))
+ else if (Value *FAD = findFADLocalNonAlloc(MemAccInst))
MemAccess->setFortranArrayDescriptor(FAD);
}
Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=303040&r1=303039&r2=303040&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Mon May 15 03:41:30 2017
@@ -1034,21 +1034,7 @@ raw_ostream &polly::operator<<(raw_ostre
return OS;
}
-void MemoryAccess::setFortranArrayDescriptor(GlobalValue *FAD) {
- this->FAD = FAD;
-
-// TODO: write checks to make sure it looks _exactly_ like a Fortran array
-// descriptor
-#ifndef NDEBUG
- StructType *ty = dyn_cast<StructType>(FAD->getValueType());
- assert(ty && "expected value of type Fortran array descriptor");
- assert(ty->hasName() && ty->getName().startswith("struct.array") &&
- "expected global to follow Fortran array descriptor type naming "
- "convention");
- assert(ty->getNumElements() == 4 &&
- "expected layout to be like Fortran array descriptor type");
-#endif
-}
+void MemoryAccess::setFortranArrayDescriptor(Value *FAD) { this->FAD = FAD; }
void MemoryAccess::print(raw_ostream &OS) const {
switch (AccType) {
Added: polly/trunk/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll?rev=303040&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll (added)
+++ polly/trunk/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll Mon May 15 03:41:30 2017
@@ -0,0 +1,67 @@
+; 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 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: ReadAccess := [Reduction Type: NONE] [Fortran array descriptor: xs] [Scalar: 0]
More information about the llvm-commits
mailing list