[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