[flang-commits] [flang] c353ebb - [flang] Compute sizes and offsets for symbols

Tim Keith via flang-commits flang-commits at lists.llvm.org
Thu Apr 23 14:56:11 PDT 2020


Author: Tim Keith
Date: 2020-04-23T14:54:34-07:00
New Revision: c353ebbfa4cb30a823fd850de97cb1ef559a05cc

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

LOG: [flang] Compute sizes and offsets for symbols

Summary:
Add size and offset properties to symbols, representing their byte size
and offset within their enclosing scope.

Add size and align properties to scopes so that they are available for
scopes representing derived types.

Add ComputeOffsets pass over the symbol table to fill in those fields.

Compute descriptor size based on rank and length parameters. Extract
DerivedTypeSpec::NumLengthParameters from DynamicType::RequiresDescriptor
to share the code.

Add Scope::GetSymbols to get symbols in canonical order.
compute-offsets.cpp and mod-file.cpp both need to process symbols in the
order in which they are declared. Move the collecting of those symbols
into Scope so that it can be shared.

Add symbol size and offset to output of `-fdebug-dump-symbols` and use
that in some tests.

Still to do:
- make size and alignment rules configurable based on target
- use offsets to check EQUIVALENCE statements

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

Added: 
    flang/lib/Semantics/compute-offsets.cpp
    flang/lib/Semantics/compute-offsets.h
    flang/test/Semantics/offsets01.f90
    flang/test/Semantics/offsets02.f90

Modified: 
    flang/include/flang/Semantics/scope.h
    flang/include/flang/Semantics/symbol.h
    flang/include/flang/Semantics/type.h
    flang/lib/Evaluate/type.cpp
    flang/lib/Semantics/CMakeLists.txt
    flang/lib/Semantics/mod-file.cpp
    flang/lib/Semantics/scope.cpp
    flang/lib/Semantics/semantics.cpp
    flang/lib/Semantics/symbol.cpp
    flang/lib/Semantics/type.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h
index 38b884e9eb0a..b653619f3542 100644
--- a/flang/include/flang/Semantics/scope.h
+++ b/flang/include/flang/Semantics/scope.h
@@ -108,12 +108,15 @@ class Scope {
   const_iterator cbegin() const { return symbols_.cbegin(); }
   const_iterator cend() const { return symbols_.cend(); }
 
+  // Return symbols in declaration order (the iterators above are in name order)
+  SymbolVector GetSymbols() const;
+  std::vector<common::Reference<Symbol>> GetSymbols();
+
   iterator find(const SourceName &name);
   const_iterator find(const SourceName &name) const {
     return symbols_.find(name);
   }
   size_type erase(const SourceName &);
-  size_type size() const { return symbols_.size(); }
   bool empty() const { return symbols_.empty(); }
 
   // Look for symbol by name in this scope and host (depending on imports).
@@ -182,6 +185,11 @@ class Scope {
   // that are referenced by SourceName objects.
   void set_chars(parser::CookedSource &);
 
+  std::size_t size() const { return size_; }
+  void set_size(std::size_t size) { size_ = size; }
+  std::size_t align() const { return align_; }
+  void set_align(std::size_t align) { align_ = align; }
+
   ImportKind GetImportKind() const;
   // Names appearing in IMPORT statements in this scope
   std::set<SourceName> importNames() const { return importNames_; }
@@ -217,6 +225,8 @@ class Scope {
 private:
   Scope &parent_; // this is enclosing scope, not extended derived type base
   const Kind kind_;
+  std::size_t size_{0}; // size in bytes
+  std::size_t align_{0}; // required alignment in bytes
   parser::CharBlock sourceRange_;
   Symbol *const symbol_; // if not null, symbol_->scope() == this
   std::list<Scope> children_;

diff  --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index 7ac48db04506..f19a97044393 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -499,6 +499,10 @@ class Symbol {
   Scope *scope() { return scope_; }
   const Scope *scope() const { return scope_; }
   void set_scope(Scope *scope) { scope_ = scope; }
+  std::size_t size() const { return size_; }
+  void set_size(std::size_t size) { size_ = size; }
+  std::size_t offset() const { return offset_; }
+  void set_offset(std::size_t offset) { offset_ = offset; }
   // Give the symbol a name with a 
diff erent source location but same chars.
   void ReplaceName(const SourceName &);
 
@@ -665,6 +669,8 @@ class Symbol {
   Attrs attrs_;
   Flags flags_;
   Scope *scope_{nullptr};
+  std::size_t size_{0}; // size in bytes
+  std::size_t offset_{0}; // byte offset in enclosing scope
   Details details_;
 
   Symbol() {} // only created in class Symbols
@@ -730,6 +736,10 @@ inline bool ProcEntityDetails::HasExplicitInterface() const {
 }
 
 inline bool operator<(SymbolRef x, SymbolRef y) { return *x < *y; }
+inline bool operator<(
+    common::Reference<Symbol> x, common::Reference<Symbol> y) {
+  return *x < *y;
+}
 using SymbolSet = std::set<SymbolRef>;
 
 } // namespace Fortran::semantics

diff  --git a/flang/include/flang/Semantics/type.h b/flang/include/flang/Semantics/type.h
index cf41721ce73b..c431a3b9731b 100644
--- a/flang/include/flang/Semantics/type.h
+++ b/flang/include/flang/Semantics/type.h
@@ -250,6 +250,7 @@ class DerivedTypeSpec {
   void ReplaceScope(const Scope &);
   RawParameters &rawParameters() { return rawParameters_; }
   const ParameterMapType &parameters() const { return parameters_; }
+  int NumLengthParameters() const;
 
   bool MightBeParameterized() const;
   bool IsForwardReferenced() const;

diff  --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp
index d1fb80f6a781..3ff085777dfa 100644
--- a/flang/lib/Evaluate/type.cpp
+++ b/flang/lib/Evaluate/type.cpp
@@ -431,28 +431,8 @@ DynamicType DynamicType::ResultTypeForMultiply(const DynamicType &that) const {
 }
 
 bool DynamicType::RequiresDescriptor() const {
-  if (IsPolymorphic() || IsUnknownLengthCharacter()) {
-    return true;
-  }
-  if (derived_) {
-    // Any length type parameter?
-    if (const auto *scope{derived_->scope()}) {
-      if (const auto *symbol{scope->symbol()}) {
-        if (const auto *details{
-                symbol->detailsIf<semantics::DerivedTypeDetails>()}) {
-          for (const Symbol &param : details->paramDecls()) {
-            if (const auto *details{
-                    param.detailsIf<semantics::TypeParamDetails>()}) {
-              if (details->attr() == common::TypeParamAttr::Len) {
-                return true;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  return false;
+  return IsPolymorphic() || IsUnknownLengthCharacter() ||
+      (derived_ && derived_->NumLengthParameters() > 0);
 }
 
 bool DynamicType::HasDeferredTypeParameter() const {

diff  --git a/flang/lib/Semantics/CMakeLists.txt b/flang/lib/Semantics/CMakeLists.txt
index 04c9cf8b31fc..aaeeca1523b4 100644
--- a/flang/lib/Semantics/CMakeLists.txt
+++ b/flang/lib/Semantics/CMakeLists.txt
@@ -21,6 +21,7 @@ add_flang_library(FortranSemantics
   check-purity.cpp
   check-return.cpp
   check-stop.cpp
+  compute-offsets.cpp
   expression.cpp
   mod-file.cpp
   pointer-assignment.cpp

diff  --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp
new file mode 100644
index 000000000000..d16d420af595
--- /dev/null
+++ b/flang/lib/Semantics/compute-offsets.cpp
@@ -0,0 +1,172 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "compute-offsets.h"
+#include "../../runtime/descriptor.h"
+#include "flang/Evaluate/fold.h"
+#include "flang/Evaluate/shape.h"
+#include "flang/Evaluate/type.h"
+#include "flang/Semantics/scope.h"
+#include "flang/Semantics/semantics.h"
+#include "flang/Semantics/symbol.h"
+#include "flang/Semantics/tools.h"
+#include "flang/Semantics/type.h"
+#include <algorithm>
+#include <vector>
+
+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} {}
+  void Compute() { Compute(context_.globalScope()); }
+
+private:
+  struct SizeAndAlign {
+    SizeAndAlign() {}
+    SizeAndAlign(std::size_t size) : size{size}, align{size} {}
+    SizeAndAlign(std::size_t size, std::size_t align)
+        : size{size}, align{align} {}
+    std::size_t size{0};
+    std::size_t align{0};
+  };
+
+  void Compute(Scope &);
+  void DoScope(Scope &);
+  void DoSymbol(Symbol &);
+  SizeAndAlign GetSizeAndAlign(const Symbol &);
+  std::size_t CountElements(const Symbol &);
+  static std::size_t Align(std::size_t, std::size_t);
+  static SizeAndAlign GetIntrinsicSizeAndAlign(TypeCategory, int);
+
+  SemanticsContext &context_;
+  evaluate::FoldingContext &foldingContext_{context_.foldingContext()};
+  std::size_t offset_{0};
+  std::size_t align_{0};
+};
+
+void ComputeOffsetsHelper::Compute(Scope &scope) {
+  for (Scope &child : scope.children()) {
+    Compute(child);
+  }
+  DoScope(scope);
+}
+
+void ComputeOffsetsHelper::DoScope(Scope &scope) {
+  if (scope.symbol() && scope.IsParameterizedDerivedType()) {
+    return; // only process instantiations of parameterized derived types
+  }
+  offset_ = 0;
+  align_ = 0;
+  for (auto symbol : scope.GetSymbols()) {
+    if (!symbol->has<TypeParamDetails>() && !symbol->has<SubprogramDetails>()) {
+      DoSymbol(*symbol);
+    }
+  }
+  scope.set_size(offset_);
+  scope.set_align(align_);
+}
+
+void ComputeOffsetsHelper::DoSymbol(Symbol &symbol) {
+  SizeAndAlign s{GetSizeAndAlign(symbol)};
+  if (s.size == 0) {
+    return;
+  }
+  offset_ = Align(offset_, s.align);
+  symbol.set_size(s.size);
+  symbol.set_offset(offset_);
+  offset_ += s.size;
+  if (s.align > align_) {
+    align_ = s.align;
+  }
+}
+
+auto ComputeOffsetsHelper::GetSizeAndAlign(const Symbol &symbol)
+    -> SizeAndAlign {
+  const DeclTypeSpec *type{symbol.GetType()};
+  if (!type) {
+    return {};
+  }
+  if (IsDescriptor(symbol) || IsProcedure(symbol)) {
+    int lenParams{0};
+    if (const DerivedTypeSpec * derived{type->AsDerived()}) {
+      lenParams = derived->NumLengthParameters();
+    }
+    std::size_t size{
+        runtime::Descriptor::SizeInBytes(symbol.Rank(), false, lenParams)};
+    return {size, maxAlignment};
+  }
+  SizeAndAlign result;
+  if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) {
+    if (auto kind{ToInt64(intrinsic->kind())}) {
+      result = GetIntrinsicSizeAndAlign(intrinsic->category(), *kind);
+    }
+    if (type->category() == DeclTypeSpec::Character) {
+      ParamValue length{type->characterTypeSpec().length()};
+      CHECK(length.isExplicit()); // else should be descriptor
+      if (MaybeIntExpr lengthExpr{length.GetExplicit()}) {
+        if (auto lengthInt{ToInt64(*lengthExpr)}) {
+          result.size *= *lengthInt;
+        }
+      }
+    }
+  } else if (const DerivedTypeSpec * derived{type->AsDerived()}) {
+    if (derived->scope()) {
+      result.size = derived->scope()->size();
+      result.align = derived->scope()->align();
+    }
+  } 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;
+}
+
+std::size_t ComputeOffsetsHelper::CountElements(const Symbol &symbol) {
+  if (auto shape{GetShape(foldingContext_, symbol)}) {
+    if (auto sizeExpr{evaluate::GetSize(std::move(*shape))}) {
+      if (auto size{ToInt64(Fold(foldingContext_, std::move(*sizeExpr)))}) {
+        return *size;
+      }
+    }
+  }
+  return 1;
+}
+
+// Align a size to its natural alignment, up to maxAlignment.
+std::size_t ComputeOffsetsHelper::Align(std::size_t x, std::size_t alignment) {
+  if (alignment > maxAlignment) {
+    alignment = maxAlignment;
+  }
+  return (x + alignment - 1) & -alignment;
+}
+
+auto ComputeOffsetsHelper::GetIntrinsicSizeAndAlign(
+    TypeCategory category, int kind) -> SizeAndAlign {
+  // TODO: does kind==10 need special handling?
+  std::size_t size{kind == 3 ? 2 : static_cast<std::size_t>(kind)};
+  if (category == TypeCategory::Complex) {
+    return {2 * size, size};
+  } else {
+    return {size};
+  }
+}
+
+void ComputeOffsets(SemanticsContext &context) {
+  ComputeOffsetsHelper{context}.Compute();
+}
+
+} // namespace Fortran::semantics

diff  --git a/flang/lib/Semantics/compute-offsets.h b/flang/lib/Semantics/compute-offsets.h
new file mode 100644
index 000000000000..2ab81713a25b
--- /dev/null
+++ b/flang/lib/Semantics/compute-offsets.h
@@ -0,0 +1,17 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 FORTRAN_SEMANTICS_COMPUTE_OFFSETS_H_
+#define FORTRAN_SEMANTICS_COMPUTE_OFFSETS_H_
+namespace Fortran::semantics {
+
+class SemanticsContext;
+void ComputeOffsets(SemanticsContext &);
+
+} // namespace Fortran::semantics
+#endif

diff  --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index 5dcc19881363..8e95b823a04f 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -414,36 +414,25 @@ void ModFileWriter::PutUseExtraAttr(
 // Collect the symbols of this scope sorted by their original order, not name.
 // Namelists are an exception: they are sorted after other symbols.
 SymbolVector CollectSymbols(const Scope &scope) {
-  SymbolSet symbols; // to prevent duplicates
   SymbolVector sorted;
   SymbolVector namelist;
-  SymbolVector common;
-  sorted.reserve(scope.size() + scope.commonBlocks().size());
-  for (const auto &pair : scope) {
-    const Symbol &symbol{*pair.second};
-    if (!symbol.test(Symbol::Flag::ParentComp)) {
-      if (symbols.insert(symbol).second) {
-        if (symbol.has<NamelistDetails>()) {
-          namelist.push_back(symbol);
-        } else {
-          sorted.push_back(symbol);
-        }
+  std::size_t commonSize{scope.commonBlocks().size()};
+  auto symbols{scope.GetSymbols()};
+  sorted.reserve(symbols.size() + commonSize);
+  for (SymbolRef symbol : symbols) {
+    if (!symbol->test(Symbol::Flag::ParentComp)) {
+      if (symbol->has<NamelistDetails>()) {
+        namelist.push_back(symbol);
+      } else {
+        sorted.push_back(symbol);
       }
     }
   }
+  sorted.insert(sorted.end(), namelist.begin(), namelist.end());
   for (const auto &pair : scope.commonBlocks()) {
-    const Symbol &symbol{*pair.second};
-    if (symbols.insert(symbol).second) {
-      common.push_back(symbol);
-    }
+    sorted.push_back(*pair.second);
   }
-  // sort normal symbols, then namelists, then common blocks:
-  auto cursor{sorted.begin()};
-  std::sort(cursor, sorted.end());
-  cursor = sorted.insert(sorted.end(), namelist.begin(), namelist.end());
-  std::sort(cursor, sorted.end());
-  cursor = sorted.insert(sorted.end(), common.begin(), common.end());
-  std::sort(cursor, sorted.end());
+  std::sort(sorted.end() - commonSize, sorted.end());
   return sorted;
 }
 

diff  --git a/flang/lib/Semantics/scope.cpp b/flang/lib/Semantics/scope.cpp
index 85307c276d84..4f89730537a0 100644
--- a/flang/lib/Semantics/scope.cpp
+++ b/flang/lib/Semantics/scope.cpp
@@ -60,6 +60,25 @@ Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
   return children_.emplace_back(*this, kind, symbol);
 }
 
+template <typename T>
+static std::vector<common::Reference<T>> GetSortedSymbols(
+    std::map<SourceName, common::Reference<Symbol>> symbols) {
+  std::vector<common::Reference<T>> result;
+  result.reserve(symbols.size());
+  for (auto &pair : symbols) {
+    result.push_back(*pair.second);
+  }
+  std::sort(result.begin(), result.end());
+  return result;
+}
+
+std::vector<common::Reference<Symbol>> Scope::GetSymbols() {
+  return GetSortedSymbols<Symbol>(symbols_);
+}
+SymbolVector Scope::GetSymbols() const {
+  return GetSortedSymbols<const Symbol>(symbols_);
+}
+
 Scope::iterator Scope::find(const SourceName &name) {
   return symbols_.find(name);
 }
@@ -292,6 +311,9 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scope &scope) {
   if (auto *symbol{scope.symbol()}) {
     os << *symbol << ' ';
   }
+  if (scope.derivedTypeSpec_) {
+    os << "instantiation of " << *scope.derivedTypeSpec_ << ' ';
+  }
   os << scope.children_.size() << " children\n";
   for (const auto &pair : scope.symbols_) {
     const Symbol &symbol{*pair.second};

diff  --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp
index cfc16149733e..19873b605762 100644
--- a/flang/lib/Semantics/semantics.cpp
+++ b/flang/lib/Semantics/semantics.cpp
@@ -26,6 +26,7 @@
 #include "check-purity.h"
 #include "check-return.h"
 #include "check-stop.h"
+#include "compute-offsets.h"
 #include "mod-file.h"
 #include "resolve-labels.h"
 #include "resolve-names.h"
@@ -161,6 +162,7 @@ static bool PerformStatementSemantics(
     SemanticsContext &context, parser::Program &program) {
   ResolveNames(context, program);
   RewriteParseTree(context, program);
+  ComputeOffsets(context);
   CheckDeclarations(context);
   StatementSemanticsPass1{context}.Walk(program);
   StatementSemanticsPass2{context}.Walk(program);
@@ -351,6 +353,12 @@ void DoDumpSymbols(llvm::raw_ostream &os, const Scope &scope, int indent) {
   if (const auto *symbol{scope.symbol()}) {
     os << ' ' << symbol->name();
   }
+  if (scope.size()) {
+    os << " size=" << scope.size() << " align=" << scope.align();
+  }
+  if (scope.derivedTypeSpec()) {
+    os << " instantiation of " << *scope.derivedTypeSpec();
+  }
   os << '\n';
   ++indent;
   for (const auto &pair : scope) {

diff  --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index 19f8b923aa38..6caadbaedc36 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -482,6 +482,9 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
   if (!symbol.flags().empty()) {
     os << " (" << symbol.flags() << ')';
   }
+  if (symbol.size_) {
+    os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
+  }
   os << ": " << symbol.details_;
   return os;
 }

diff  --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index 3a98dda7916d..40518ce24ba1 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -160,6 +160,16 @@ void DerivedTypeSpec::AddParamValue(SourceName name, ParamValue &&value) {
   CHECK(pair.second); // name was not already present
 }
 
+int DerivedTypeSpec::NumLengthParameters() const {
+  int result{0};
+  for (const auto &pair : parameters_) {
+    if (pair.second.isLen()) {
+      ++result;
+    }
+  }
+  return result;
+}
+
 bool DerivedTypeSpec::MightBeParameterized() const {
   return !cooked_ || !parameters_.empty();
 }

diff  --git a/flang/test/Semantics/offsets01.f90 b/flang/test/Semantics/offsets01.f90
new file mode 100644
index 000000000000..aa4f79612834
--- /dev/null
+++ b/flang/test/Semantics/offsets01.f90
@@ -0,0 +1,52 @@
+!RUN: %f18 -fdebug-dump-symbols -fparse-only %s | FileCheck %s
+
+! Size and alignment of intrinsic types
+subroutine s1
+  integer(1) :: a_i1  !CHECK: a_i1 size=1 offset=0:
+  integer(8) :: b_i8  !CHECK: b_i8 size=8 offset=8:
+  real(2)    :: c_r2  !CHECK: c_r2 size=2 offset=16:
+  real(2)    :: d_r2  !CHECK: d_r2 size=2 offset=18:
+  real(8)    :: e_r8  !CHECK: e_r8 size=8 offset=24:
+  real(4)    :: f_r4  !CHECK: f_r4 size=4 offset=32:
+  complex(8) :: g_c8  !CHECK: g_c8 size=16 offset=40:
+  complex(4) :: h_c4  !CHECK: h_c4 size=8 offset=56:
+  logical    :: i_l4  !CHECK: i_l4 size=4 offset=64:
+end
+
+! Character
+subroutine s2
+  character(10)        :: c1 !CHECK: c1 size=10 offset=0:
+  character(1)         :: c2 !CHECK: c2 size=1 offset=10:
+  character(10,kind=2) :: c3 !CHECK: c3 size=20 offset=12:
+end
+
+! Descriptors
+subroutine s3(n)
+  integer :: n
+  real, pointer :: x !CHECK: x, POINTER size=24 offset=8:
+  character(n)  :: y !CHECK: y size=24 offset=32:
+end
+
+! Descriptors for arrays
+subroutine s4
+  integer, allocatable :: z0        !CHECK: z0, ALLOCATABLE size=24 offset=
+  integer, allocatable :: z1(:)     !CHECK: z1, ALLOCATABLE size=48 offset=
+  integer, allocatable :: z2(:,:)   !CHECK: z2, ALLOCATABLE size=72 offset=
+  integer, allocatable :: z3(:,:,:) !CHECK: z3, ALLOCATABLE size=96 offset=
+end
+
+! Descriptors with length parameters
+subroutine s5(n)
+  integer :: n
+  type :: t1(l)
+    integer, len :: l
+    real :: a(l)
+  end type
+  type :: t2(l1, l2)
+    integer, len :: l1
+    integer, len :: l2
+    real :: b(l1, l2)
+  end type
+  type(t1(n))   :: x1 !CHECK: x1 size=48 offset=
+  type(t2(n,n)) :: x2 !CHECK: x2 size=56 offset=
+end

diff  --git a/flang/test/Semantics/offsets02.f90 b/flang/test/Semantics/offsets02.f90
new file mode 100644
index 000000000000..ef7f306c378e
--- /dev/null
+++ b/flang/test/Semantics/offsets02.f90
@@ -0,0 +1,54 @@
+!RUN: %f18 -fdebug-dump-symbols -fparse-only %s | FileCheck %s
+
+! Size and alignment of derived types
+
+! Array of derived type with 64-bit alignment
+subroutine s1
+  type t1
+    real(8) :: a
+    real(4) :: b
+  end type
+  !CHECK: x1 size=12 offset=0:
+  !CHECK: y1 size=12 offset=16:
+  type(t1) :: x1, y1
+  !CHECK: z1 size=160 offset=32:
+  type(t1) :: z1(10)
+end
+
+! Like t1 but t2 does not need to be aligned on 64-bit boundary
+subroutine s2
+  type t2
+    real(4) :: a
+    real(4) :: b
+    real(4) :: c
+  end type
+  !CHECK: x2 size=12 offset=0:
+  !CHECK: y2 size=12 offset=12:
+  type(t2) :: x2, y2
+  !CHECK: z2 size=120 offset=24:
+  type(t2) :: z2(10)
+end
+
+! Parameterized derived types
+subroutine s3
+  type :: t(k, l)
+    integer, kind :: k
+    integer, len :: l
+    real(k) :: a3
+    integer(kind=k) :: b3
+    character(kind=k, len=8) :: c3
+    character(kind=k, len=l) :: d3
+  end type
+  !CHECK: DerivedType scope: size=48 align=8 instantiation of t(k=2_4,l=10_4)
+  !CHECK: a3 size=2 offset=0:
+  !CHECK: b3 size=2 offset=2:
+  !CHECK: c3 size=16 offset=4:
+  !CHECK: d3 size=24 offset=24:
+  type(t(2, 10)) :: x3
+  !CHECK: DerivedType scope: size=64 align=8 instantiation of t(k=4_4,l=20_4)
+  !CHECK: a3 size=4 offset=0:
+  !CHECK: b3 size=4 offset=4:
+  !CHECK: c3 size=32 offset=8:
+  !CHECK: d3 size=24 offset=40:
+  type(t(4, 20)) :: x4
+end


        


More information about the flang-commits mailing list