[flang] Implement and test RESHAPE.  Avoid G++ workaround when compiled with GNU 8.2.0.

Original-commit: flang-compiler/f18@80257ee0d2747796675e21975849125b0c0a6f4e
Reviewed-on: https://github.com/flang-compiler/f18/pull/162
Tree-same-pre-rewrite: false
diff --git a/flang/runtime/transformational.cc b/flang/runtime/transformational.cc
new file mode 100644
index 0000000..b677a90
--- /dev/null
+++ b/flang/runtime/transformational.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "descriptor.h"
+#include "../lib/common/idioms.h"
+#include "../lib/evaluate/integer.h"
+#include <algorithm>
+#include <bitset>
+#include <cinttypes>
+#include <cstdlib>
+
+namespace Fortran::runtime {
+
+template<int BITS> inline std::int64_t LoadInt64(const char *p) {
+  using Int = const evaluate::value::Integer<BITS>;
+  Int *ip{reinterpret_cast<Int *>(p)};
+  return ip->ToInt64();
+}
+
+static inline std::int64_t GetInt64(const char *p, std::size_t bytes) {
+  switch (bytes) {
+  case 1: return LoadInt64<8>(p);
+  case 2: return LoadInt64<16>(p);
+  case 4: return LoadInt64<32>(p);
+  case 8: return LoadInt64<64>(p);
+  default: CRASH_NO_CASE;
+  }
+}
+
+// F2018 16.9.163
+Descriptor *RESHAPE(const Descriptor &source, const Descriptor &shape,
+    const Descriptor *pad, const Descriptor *order) {
+  // Compute and check the rank of the result.
+  CHECK(shape.rank() == 1);
+  CHECK(shape.type().IsInteger());
+  SubscriptValue resultRank{shape.GetDimension(0).Extent()};
+  CHECK(resultRank >= 0 && resultRank <= static_cast<SubscriptValue>(maxRank));
+
+  // Extract and check the shape of the result; compute its element count.
+  SubscriptValue resultExtent[maxRank];
+  std::size_t shapeElementBytes{shape.ElementBytes()};
+  std::size_t resultElements{1};
+  SubscriptValue shapeSubscript{shape.GetDimension(0).LowerBound()};
+  for (SubscriptValue j{0}; j < resultRank; ++j, ++shapeSubscript) {
+    resultExtent[j] =
+        GetInt64(shape.Element<char>(&shapeSubscript), shapeElementBytes);
+    CHECK(resultExtent[j] >= 0);
+    resultElements *= resultExtent[j];
+  }
+
+  // Check that there are sufficient elements in the SOURCE=, or that
+  // the optional PAD= argument is present and nonempty.
+  std::size_t sourceElements{source.Elements()};
+  std::size_t padElements{pad ? pad->Elements() : 0};
+  if (resultElements < sourceElements) {
+    CHECK(padElements > 0);
+    CHECK(pad->ElementBytes() == source.ElementBytes());
+  }
+
+  // Extract and check the optional ORDER= argument, which must be a
+  // permutation of [1..resultRank].
+  int dimOrder[maxRank];
+  if (order != nullptr) {
+    CHECK(order->rank() == 1);
+    CHECK(order->type().IsInteger());
+    CHECK(order->GetDimension(0).Extent() == resultRank);
+    std::bitset<maxRank> values;
+    SubscriptValue orderSubscript{order->GetDimension(0).LowerBound()};
+    for (SubscriptValue j{0}; j < resultRank; ++j, ++orderSubscript) {
+      auto k{GetInt64(order->Element<char>(orderSubscript), shapeElementBytes)};
+      CHECK(k >= 1 && k <= resultRank && !values.test(k - 1));
+      values.set(k - 1);
+      dimOrder[k - 1] = j;
+    }
+  } else {
+    for (int j{0}; j < resultRank; ++j) {
+      dimOrder[j] = j;
+    }
+  }
+
+  // Allocate the result's data storage.
+  std::size_t elementBytes{source.ElementBytes()};
+  std::size_t resultBytes{resultElements * elementBytes};
+  void *data{std::malloc(resultBytes)};
+  CHECK(resultBytes == 0 || data != nullptr);
+
+  // Create and populate the result's descriptor.
+  const DescriptorAddendum *sourceAddendum{source.Addendum()};
+  const DerivedType *sourceDerivedType{
+      sourceAddendum ? sourceAddendum->derivedType() : nullptr};
+  Descriptor *result{nullptr};
+  if (sourceDerivedType != nullptr) {
+    result =
+        Descriptor::Create(*sourceDerivedType, data, resultRank, resultExtent);
+  } else {
+    result = Descriptor::Create(
+        source.type(), elementBytes, data, resultRank, resultExtent);
+  }
+  DescriptorAddendum *resultAddendum{result->Addendum()};
+  CHECK(resultAddendum != nullptr);
+  resultAddendum->flags() |= DescriptorAddendum::DoNotFinalize;
+  resultAddendum->flags() |= DescriptorAddendum::AllContiguous;
+  if (sourceDerivedType != nullptr) {
+    std::size_t lenParameters{sourceDerivedType->lenParameters()};
+    for (std::size_t j{0}; j < lenParameters; ++j) {
+      resultAddendum->SetLenParameterValue(
+          j, sourceAddendum->LenParameterValue(j));
+    }
+  }
+
+  // Populate the result's elements.
+  SubscriptValue resultSubscript[maxRank];
+  result->GetLowerBounds(resultSubscript);
+  SubscriptValue sourceSubscript[maxRank];
+  source.GetLowerBounds(sourceSubscript);
+  std::size_t resultElement{0};
+  std::size_t elementsFromSource{std::min(resultElements, sourceElements)};
+  for (; resultElement < elementsFromSource; ++resultElement) {
+    std::memcpy(result->Element<void>(resultSubscript),
+        source.Element<const void>(sourceSubscript), elementBytes);
+    source.IncrementSubscripts(sourceSubscript);
+    result->IncrementSubscripts(resultSubscript, dimOrder);
+  }
+  if (resultElement < resultElements) {
+    // Remaining elements come from the optional PAD= argument.
+    SubscriptValue padSubscript[maxRank];
+    pad->GetLowerBounds(padSubscript);
+    for (; resultElement < resultElements; ++resultElement) {
+      std::memcpy(result->Element<void>(resultSubscript),
+          pad->Element<const void>(padSubscript), elementBytes);
+      pad->IncrementSubscripts(padSubscript);
+      result->IncrementSubscripts(resultSubscript, dimOrder);
+    }
+  }
+
+  return result;
+}
+
+}  // namespace Fortran::runtime