[flang-commits] [flang] 237d0e3 - [flang] Handle EQUIVALENCE and COMMON in size and offset computations

Tim Keith via flang-commits flang-commits at lists.llvm.org
Wed May 6 11:46:06 PDT 2020


Author: Tim Keith
Date: 2020-05-06T11:45:28-07:00
New Revision: 237d0e3c0416abf9919406bcc92874cfd15f5e0c

URL: https://github.com/llvm/llvm-project/commit/237d0e3c0416abf9919406bcc92874cfd15f5e0c
DIFF: https://github.com/llvm/llvm-project/commit/237d0e3c0416abf9919406bcc92874cfd15f5e0c.diff

LOG: [flang] Handle EQUIVALENCE and COMMON in size and offset computations

Objects in common blocks have offsets relative to the start of the
common block, independent of the enclosing scope, so they are processed
first. Add alignment to CommonBlockDetails to record the required
alignment of the common block.

For equivalence sets, each object depends on the one that is forced to
occur first in memory. The rest are recorded in the dependents_ map and
have offsets assigned after the other symbols are done.

Differential Revision: https://reviews.llvm.org/D79347

Added: 
    flang/test/Semantics/offsets03.f90

Modified: 
    flang/include/flang/Semantics/symbol.h
    flang/lib/Semantics/compute-offsets.cpp
    flang/lib/Semantics/symbol.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index f19a97044393..4b22e57c0690 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -303,10 +303,13 @@ class CommonBlockDetails {
   void add_object(const Symbol &object) { objects_.emplace_back(object); }
   MaybeExpr bindName() const { return bindName_; }
   void set_bindName(MaybeExpr &&expr) { bindName_ = std::move(expr); }
+  std::size_t align() const { return align_; }
+  void set_align(std::size_t align) { align_ = align; }
 
 private:
   SymbolVector objects_;
   MaybeExpr bindName_;
+  std::size_t align_{0}; // required alignment in bytes
 };
 
 class FinalProcDetails {}; // TODO
@@ -670,7 +673,7 @@ class Symbol {
   Flags flags_;
   Scope *scope_{nullptr};
   std::size_t size_{0}; // size in bytes
-  std::size_t offset_{0}; // byte offset in enclosing scope
+  std::size_t offset_{0}; // byte offset in scope or common block
   Details details_;
 
   Symbol() {} // only created in class Symbols

diff  --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp
index d16d420af595..ae5481cdc548 100644
--- a/flang/lib/Semantics/compute-offsets.cpp
+++ b/flang/lib/Semantics/compute-offsets.cpp
@@ -24,7 +24,6 @@ namespace Fortran::semantics {
 class ComputeOffsetsHelper {
 public:
   // TODO: configure based on target
-  static constexpr int descriptorSize{3 * 8};
   static constexpr int maxAlignment{8};
 
   ComputeOffsetsHelper(SemanticsContext &context) : context_{context} {}
@@ -39,11 +38,20 @@ class ComputeOffsetsHelper {
     std::size_t size{0};
     std::size_t align{0};
   };
+  struct SymbolAndOffset {
+    Symbol *symbol{nullptr};
+    std::size_t offset{0};
+  };
 
   void Compute(Scope &);
   void DoScope(Scope &);
+  void DoCommonBlock(Symbol &);
+  void DoEquivalenceSet(EquivalenceSet &);
+  std::size_t GetOffset(SymbolAndOffset &);
+  std::size_t ComputeOffset(const EquivalenceObject &);
   void DoSymbol(Symbol &);
   SizeAndAlign GetSizeAndAlign(const Symbol &);
+  SizeAndAlign GetElementSize(const Symbol &, bool isSubstring = false);
   std::size_t CountElements(const Symbol &);
   static std::size_t Align(std::size_t, std::size_t);
   static SizeAndAlign GetIntrinsicSizeAndAlign(TypeCategory, int);
@@ -52,6 +60,8 @@ class ComputeOffsetsHelper {
   evaluate::FoldingContext &foldingContext_{context_.foldingContext()};
   std::size_t offset_{0};
   std::size_t align_{0};
+  // symbol -> symbol+offset that determines its location, from EQUIVALENCE
+  std::map<MutableSymbolRef, SymbolAndOffset> dependents_;
 };
 
 void ComputeOffsetsHelper::Compute(Scope &scope) {
@@ -61,22 +71,116 @@ void ComputeOffsetsHelper::Compute(Scope &scope) {
   DoScope(scope);
 }
 
+static bool InCommonBlock(const Symbol &symbol) {
+  const auto *details{symbol.detailsIf<ObjectEntityDetails>()};
+  return details && details->commonBlock();
+}
+
 void ComputeOffsetsHelper::DoScope(Scope &scope) {
   if (scope.symbol() && scope.IsParameterizedDerivedType()) {
     return; // only process instantiations of parameterized derived types
   }
+  // Symbols in common block get offsets from the beginning of the block
+  for (auto &pair : scope.commonBlocks()) {
+    DoCommonBlock(*pair.second);
+  }
+  // Build dependents_ from equivalences: symbol -> symbol+offset
+  for (EquivalenceSet &set : scope.equivalenceSets()) {
+    DoEquivalenceSet(set);
+  }
   offset_ = 0;
   align_ = 0;
-  for (auto symbol : scope.GetSymbols()) {
-    if (!symbol->has<TypeParamDetails>() && !symbol->has<SubprogramDetails>()) {
+  for (auto &symbol : scope.GetSymbols()) {
+    if (!InCommonBlock(*symbol) &&
+        dependents_.find(symbol) == dependents_.end()) {
       DoSymbol(*symbol);
     }
   }
+  for (auto &[symbol, dep] : dependents_) {
+    if (symbol->size() == 0) {
+      SizeAndAlign s{GetSizeAndAlign(*symbol)};
+      symbol->set_size(s.size);
+      symbol->set_offset(GetOffset(dep));
+      offset_ = std::max(offset_, symbol->offset() + symbol->size());
+    }
+  }
   scope.set_size(offset_);
   scope.set_align(align_);
 }
 
+std::size_t ComputeOffsetsHelper::GetOffset(SymbolAndOffset &dep) {
+  auto it{dependents_.find(*dep.symbol)};
+  if (it == dependents_.end()) {
+    return dep.symbol->offset() + dep.offset;
+  } else {
+    return GetOffset(it->second) + dep.offset;
+  }
+}
+
+void ComputeOffsetsHelper::DoCommonBlock(Symbol &commonBlock) {
+  auto &details{commonBlock.get<CommonBlockDetails>()};
+  offset_ = 0;
+  align_ = 0;
+  for (auto &object : details.objects()) {
+    DoSymbol(*object);
+  }
+  commonBlock.set_size(offset_);
+  details.set_align(align_);
+}
+
+void ComputeOffsetsHelper::DoEquivalenceSet(EquivalenceSet &set) {
+  std::vector<SymbolAndOffset> symbolOffsets;
+  SymbolAndOffset max;
+  for (EquivalenceObject &object : set) {
+    std::size_t offset{ComputeOffset(object)};
+    symbolOffsets.push_back({&object.symbol, offset});
+    if (offset >= max.offset) {
+      max.offset = offset;
+      max.symbol = &object.symbol;
+    }
+  }
+  CHECK(max.symbol);
+  for (auto &[symbol, offset] : symbolOffsets) {
+    if (symbol != max.symbol) {
+      dependents_.emplace(
+          *symbol, SymbolAndOffset{max.symbol, max.offset - offset});
+    }
+  }
+}
+
+// Offset of this equivalence object from the start of its variable.
+std::size_t ComputeOffsetsHelper::ComputeOffset(
+    const EquivalenceObject &object) {
+  std::size_t offset{0};
+  if (object.substringStart) {
+    offset = *object.substringStart - 1;
+  }
+  if (!object.subscripts.empty()) {
+    const ArraySpec &shape{object.symbol.get<ObjectEntityDetails>().shape()};
+    auto lbound{[&](std::size_t i) {
+      return *ToInt64(shape[i].lbound().GetExplicit());
+    }};
+    auto ubound{[&](std::size_t i) {
+      return *ToInt64(shape[i].ubound().GetExplicit());
+    }};
+    for (std::size_t i{object.subscripts.size() - 1};;) {
+      offset += object.subscripts[i] - lbound(i);
+      if (i == 0) {
+        break;
+      }
+      --i;
+      offset *= ubound(i) - lbound(i) + 1;
+    }
+  }
+  return offset *
+      GetElementSize(object.symbol, object.substringStart.has_value()).size;
+}
+
 void ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
+  if (symbol.has<TypeParamDetails>() || symbol.has<SubprogramDetails>() ||
+      symbol.has<UseDetails>() || symbol.has<ProcBindingDetails>()) {
+    return; // these have type but no size
+  }
   SizeAndAlign s{GetSizeAndAlign(symbol)};
   if (s.size == 0) {
     return;
@@ -85,13 +189,22 @@ void ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
   symbol.set_size(s.size);
   symbol.set_offset(offset_);
   offset_ += s.size;
-  if (s.align > align_) {
-    align_ = s.align;
-  }
+  align_ = std::max(align_, s.align);
 }
 
 auto ComputeOffsetsHelper::GetSizeAndAlign(const Symbol &symbol)
     -> SizeAndAlign {
+  SizeAndAlign result{GetElementSize(symbol)};
+  std::size_t elements{CountElements(symbol)};
+  if (elements > 1) {
+    result.size = Align(result.size, result.align);
+  }
+  result.size *= elements;
+  return result;
+}
+
+auto ComputeOffsetsHelper::GetElementSize(
+    const Symbol &symbol, bool isSubstring) -> SizeAndAlign {
   const DeclTypeSpec *type{symbol.GetType()};
   if (!type) {
     return {};
@@ -110,7 +223,7 @@ auto ComputeOffsetsHelper::GetSizeAndAlign(const Symbol &symbol)
     if (auto kind{ToInt64(intrinsic->kind())}) {
       result = GetIntrinsicSizeAndAlign(intrinsic->category(), *kind);
     }
-    if (type->category() == DeclTypeSpec::Character) {
+    if (!isSubstring && type->category() == DeclTypeSpec::Character) {
       ParamValue length{type->characterTypeSpec().length()};
       CHECK(length.isExplicit()); // else should be descriptor
       if (MaybeIntExpr lengthExpr{length.GetExplicit()}) {
@@ -127,11 +240,6 @@ auto ComputeOffsetsHelper::GetSizeAndAlign(const Symbol &symbol)
   } else {
     DIE("not intrinsic or derived");
   }
-  std::size_t elements{CountElements(symbol)};
-  if (elements > 1) {
-    result.size = Align(result.size, result.align);
-  }
-  result.size *= elements;
   return result;
 }
 

diff  --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index 6caadbaedc36..35a3197963c3 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -434,6 +434,9 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
             DumpSymbolVector(os, x.objects());
           },
           [&](const CommonBlockDetails &x) {
+            if (x.align()) {
+              os << " align=" << x.align();
+            }
             os << ':';
             for (const Symbol &object : x.objects()) {
               os << ' ' << object.name();

diff  --git a/flang/test/Semantics/offsets03.f90 b/flang/test/Semantics/offsets03.f90
new file mode 100644
index 000000000000..b10bce71f018
--- /dev/null
+++ b/flang/test/Semantics/offsets03.f90
@@ -0,0 +1,39 @@
+!RUN: %f18 -fdebug-dump-symbols -fparse-only %s | FileCheck %s
+
+! Size and alignment with EQUIVALENCE and COMMON
+
+! a1 depends on a2 depends on a3
+module ma
+  real :: a1(10), a2(10), a3(10)
+  equivalence(a1, a2(3)) !CHECK: a1, PUBLIC size=40 offset=20:
+  equivalence(a2, a3(4)) !CHECK: a2, PUBLIC size=40 offset=12:
+  !CHECK: a3, PUBLIC size=40 offset=0:
+end
+
+! equivalence and 2-dimensional array
+module mb
+  real :: b1(4), b2, b3, b4
+  real :: b(-1:1,2:6)     !CHECK: b, PUBLIC size=60 offset=0:
+  equivalence(b(1,6), b1) !CHECK: b1, PUBLIC size=16 offset=56:
+  equivalence(b(1,5), b2) !CHECK: b2, PUBLIC size=4 offset=44:
+  equivalence(b(0,6), b3) !CHECK: b3, PUBLIC size=4 offset=52:
+  equivalence(b(0,4), b4) !CHECK: b4, PUBLIC size=4 offset=28:
+end
+
+! equivalence and substring
+subroutine mc         !CHECK: Subprogram scope: mc size=12 align=1
+  character(10) :: c1 !CHECK: c1 size=10 offset=0:
+  character(5)  :: c2 !CHECK: c2 size=5 offset=7:
+  equivalence(c1(9:), c2(2:4))
+end
+
+! Common block: objects are in order from COMMON statement and not part of module
+module md                   !CHECK: Module scope: md size=1 align=1
+  integer(1) :: i 
+  integer(2) :: d1          !CHECK: d1, PUBLIC size=2 offset=8:
+  integer(4) :: d2          !CHECK: d2, PUBLIC size=4 offset=4:
+  integer(1) :: d3          !CHECK: d3, PUBLIC size=1 offset=0:
+  real(2) :: d4             !CHECK: d4, PUBLIC size=2 offset=0:
+  common /common1/ d3,d2,d1 !CHECK: common1 size=10 offset=0: CommonBlockDetails align=4:
+  common /common2/ d4       !CHECK: common2 size=2 offset=0: CommonBlockDetails align=2:
+end


        


More information about the flang-commits mailing list