[flang] Fixed CFI_establish. Improved and renamed related test suit
authorJean Perier <jperier@hsw1.pgi.net>
Mon, 5 Nov 2018 15:07:18 +0000 (07:07 -0800)
committerJean Perier <jperier@hsw1.pgi.net>
Mon, 5 Nov 2018 15:07:18 +0000 (07:07 -0800)
Original-commit: flang-compiler/f18@b75d858e4f96c21da67a8c7ecc4d4bdbcc9c8498
Reviewed-on: https://github.com/flang-compiler/f18/pull/222
Tree-same-pre-rewrite: false

flang/runtime/ISO_Fortran_binding.cc
flang/test/evaluate/CFI_functions.cc [deleted file]
flang/test/evaluate/CMakeLists.txt
flang/test/evaluate/ISO-Fortran-binding.cc [new file with mode: 0644]

index 81a8f0c..088e328 100644 (file)
@@ -133,7 +133,6 @@ static constexpr std::size_t MinElemLen(CFI_type_t type) {
     minElemLen = 2 * sizeof(long double);
     break;
   case CFI_type_Bool: minElemLen = 1; break;
-  case CFI_type_char: minElemLen = sizeof(char); break;
   }
   return minElemLen;
 }
@@ -148,7 +147,7 @@ int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr,
   if (rank > CFI_MAX_RANK) {
     return CFI_INVALID_RANK;
   }
-  if (base_addr != nullptr && attribute != CFI_attribute_pointer) {
+  if (base_addr != nullptr && attribute == CFI_attribute_allocatable) {
     return CFI_ERROR_BASE_ADDR_NOT_NULL;
   }
   if (rank > 0 && base_addr != nullptr && extents == nullptr) {
@@ -171,11 +170,14 @@ int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr,
   descriptor->attribute = attribute;
   descriptor->f18Addendum = 0;
   std::size_t byteSize{elem_len};
-  for (std::size_t j{0}; j < rank; ++j) {
-    descriptor->dim[j].lower_bound = 1;
-    descriptor->dim[j].extent = extents[j];
-    descriptor->dim[j].sm = byteSize;
-    byteSize *= extents[j];
+  std::size_t lower_bound{attribute!=CFI_attribute_pointer};
+  if (base_addr !=nullptr) {
+    for (std::size_t j{0}; j < rank; ++j) {
+      descriptor->dim[j].lower_bound = lower_bound;
+      descriptor->dim[j].extent = extents[j];
+      descriptor->dim[j].sm = byteSize;
+      byteSize *= extents[j];
+    }
   }
   return CFI_SUCCESS;
 }
diff --git a/flang/test/evaluate/CFI_functions.cc b/flang/test/evaluate/CFI_functions.cc
deleted file mode 100644 (file)
index d5a01f9..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-// 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 "testing.h"
-#include "../../include/flang/ISO_Fortran_binding.h"
-#include "../../runtime/descriptor.h"
-#include <iostream>
-#include <type_traits>
-
-using namespace Fortran::runtime;
-using namespace Fortran::ISO;
-
-int check_CFI_establish(CFI_cdesc_t *dv, void *base_addr,
-    CFI_attribute_t attribute, CFI_type_t type, std::size_t elem_len,
-    CFI_rank_t rank, const CFI_index_t extents[]) {
-  // CFI_establish reqs from F2018 section 18.5.5
-  int ret_code =
-      CFI_establish(dv, base_addr, attribute, type, elem_len, rank, extents);
-  Descriptor *res = reinterpret_cast<Descriptor *>(dv);
-  if (ret_code == CFI_SUCCESS) {
-    res->Check();
-    MATCH(res->IsPointer(), (attribute == CFI_attribute_pointer));
-    MATCH(res->IsAllocatable(), (attribute == CFI_attribute_allocatable));
-    MATCH(res->IsContiguous(), true);
-    MATCH(res->rank(), rank);
-    std::size_t head{0};
-    MATCH(reinterpret_cast<std::intptr_t>(res->Element<char>(head)),
-        reinterpret_cast<std::intptr_t>(base_addr));
-    if (base_addr != nullptr) {
-      for (int i{0}; i < rank; ++i) {
-        MATCH(res->GetDimension(i).Extent(), extents[i]);
-      }
-    }
-    if (attribute == CFI_attribute_allocatable) {
-      MATCH(res->IsAllocated(), false);
-    }
-    if (attribute == CFI_attribute_pointer) {
-      if (base_addr != nullptr) {
-        // TODO should also be checked for Fortran character types and
-        // CFI_type_other
-        for (int i{0}; i < rank; ++i) {
-          MATCH(res->GetDimension(i).LowerBound(), 0);
-        }
-      }
-    }
-    if (type == CFI_type_struct) {
-      MATCH(elem_len, res->ElementBytes());
-    }
-  }
-  return ret_code;
-}
-
-void add_noise_to_cdesc(CFI_cdesc_t *dv, CFI_rank_t rank) {
-  static int trap;
-  dv->rank = 16;
-  dv->base_addr = reinterpret_cast<void *>(&trap);
-  dv->elem_len = 320;
-  dv->type = CFI_type_struct;
-  dv->attribute = CFI_attribute_pointer;
-  for (int i{0}; i < rank; i++) {
-    dv->dim[i].extent = -42;
-    dv->dim[i].lower_bound = -42;
-    dv->dim[i].sm = -42;
-  }
-}
-
-int main() {
-  const int rank{3};
-  static const CFI_index_t extents[]{2, 3, 66};
-  CFI_CDESC_T(rank) dv_3darray_storage;
-  static CFI_CDESC_T(0) dv_scalar_storage;
-  CFI_cdesc_t *dv_3darray{reinterpret_cast<CFI_cdesc_t *>(&dv_3darray_storage)};
-  CFI_cdesc_t *dv_scalar{reinterpret_cast<CFI_cdesc_t *>(&dv_scalar_storage)};
-  CFI_attribute_t attr_cases[]{
-      CFI_attribute_pointer, CFI_attribute_allocatable, CFI_attribute_other};
-  CFI_attribute_t nonalloctable_cases[]{
-      CFI_attribute_pointer, CFI_attribute_other};
-  CFI_type_t type_cases[]{CFI_type_int, CFI_type_struct, CFI_type_double};
-  int ret_code = CFI_INVALID_DESCRIPTOR;
-  // Test CFI_CDESC_T macro defined in section 18.5.4 of F2018 standard
-  // CFI_CDESC_T must give storage that is:
-  // unqualified
-  MATCH(std::is_const<decltype(dv_3darray_storage)>::value, false);
-  MATCH(std::is_volatile<decltype(dv_3darray_storage)>::value, false);
-  // suitable in size
-  MATCH(sizeof(decltype(dv_3darray_storage)),
-      Descriptor::SizeInBytes(rank, false));
-  MATCH(sizeof(decltype(dv_scalar_storage)), Descriptor::SizeInBytes(0, false));
-  // suitable in alignment
-  MATCH(reinterpret_cast<std::uintptr_t>(&dv_3darray_storage) &
-          (alignof(CFI_cdesc_t) - 1),
-      0);
-  MATCH(reinterpret_cast<std::uintptr_t>(&dv_scalar_storage) &
-          (alignof(CFI_cdesc_t) - 1),
-      0);
-
-  // Testing CFI_establish definied in section 18.5.5
-  for (CFI_attribute_t attribute : attr_cases) {
-    for (CFI_type_t type : type_cases) {
-      add_noise_to_cdesc(dv_3darray, rank);
-      ret_code = check_CFI_establish(
-          dv_3darray, nullptr, attribute, type, 42, rank, extents);
-      MATCH(ret_code, CFI_SUCCESS);
-      add_noise_to_cdesc(dv_scalar, 0);
-      ret_code = check_CFI_establish(
-          dv_scalar, nullptr, attribute, type, 42, 0, extents);
-      MATCH(ret_code, CFI_SUCCESS);
-    }
-  }
-  // If base_addr is null, extents shall be ignored even if rank !=0
-  add_noise_to_cdesc(dv_3darray, rank);  // => dv_3darray->dim[2].extent = -42
-  ret_code = check_CFI_establish(
-      dv_3darray, nullptr, CFI_attribute_other, CFI_type_int, 4, rank, extents);
-  MATCH(false,
-      dv_3darray->dim[2].extent ==
-          66);  // extents was read even if could have been null
-
-  static char base;
-  void *base_addr = reinterpret_cast<void *>(&base);
-  // arg base_addr shall be null if the attribute arg is allocatable, else OK
-  add_noise_to_cdesc(dv_3darray, rank);
-  ret_code = check_CFI_establish(dv_3darray, base_addr,
-      CFI_attribute_allocatable, CFI_type_int, 4, rank, extents);
-  MATCH(true, ret_code == CFI_ERROR_BASE_ADDR_NOT_NULL);
-  add_noise_to_cdesc(dv_scalar, 0);
-  ret_code = check_CFI_establish(dv_3darray, base_addr,
-      CFI_attribute_allocatable, CFI_type_int, 4, rank, extents);
-  MATCH(true, ret_code == CFI_ERROR_BASE_ADDR_NOT_NULL);
-
-  for (CFI_attribute_t attribute : nonalloctable_cases) {
-    for (CFI_type_t type : type_cases) {
-      add_noise_to_cdesc(dv_3darray, rank);
-      ret_code = check_CFI_establish(
-          dv_3darray, base_addr, attribute, type, 42, rank, extents);
-      MATCH(ret_code, CFI_SUCCESS);
-      add_noise_to_cdesc(dv_scalar, 0);
-      ret_code = check_CFI_establish(
-          dv_scalar, base_addr, attribute, type, 42, 0, nullptr);
-      MATCH(ret_code, CFI_SUCCESS);
-    }
-  }
-  // TODO: check invalid rank and type
-
-  typedef struct {
-    double x;
-    double _Complex y;
-  } t;
-  // TODO: test CFI_address
-  // TODO: test CFI_allocate
-  // TODO: test CFI_deallocate
-  // TODO: test CFI_establish
-  // TODO: test CFI_is_contiguous
-  // TODO: test CFI_section
-  // TODO: test CFI_select_part
-  // TODO: test CFI_setpointer
-  return testing::Complete();
-}
index 922979e..0fadf3b 100644 (file)
@@ -98,15 +98,16 @@ target_link_libraries(reshape-test
   FortranRuntime
 )
 
-add_executable(CFI_functions-test
-  CFI_functions.cc
+add_executable(ISO-Fortran-binding-test
+  ISO-Fortran-binding.cc
 )
 
-target_link_libraries(CFI_functions-test
+target_link_libraries(ISO-Fortran-binding-test
   FortranEvaluate
   FortranEvaluateTesting
   FortranRuntime
 )
+
 add_test(NAME Expression COMMAND expression-test)
 add_test(NAME Leadz COMMAND leading-zero-bit-count-test)
 add_test(NAME PopPar COMMAND bit-population-count-test)
@@ -115,4 +116,4 @@ add_test(NAME Intrinsics COMMAND intrinsics-test)
 add_test(NAME Logical COMMAND logical-test)
 add_test(NAME Real COMMAND real-test)
 add_test(NAME RESHAPE COMMAND reshape-test)
-add_test(NAME CFI_functions COMMAND CFI_functions-test)
+add_test(NAME ISO-Fortran-binding COMMAND ISO-Fortran-binding-test)
diff --git a/flang/test/evaluate/ISO-Fortran-binding.cc b/flang/test/evaluate/ISO-Fortran-binding.cc
new file mode 100644 (file)
index 0000000..b9046ef
--- /dev/null
@@ -0,0 +1,200 @@
+// 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 "testing.h"
+#include "../../include/flang/ISO_Fortran_binding.h"
+#include "../../runtime/descriptor.h"
+#include <type_traits>
+#ifdef VERBOSE
+#include <iostream>
+#endif
+
+using namespace Fortran::runtime;
+using namespace Fortran::ISO;
+
+static int check_CFI_establish(CFI_cdesc_t *dv, void *base_addr,
+    CFI_attribute_t attribute, CFI_type_t type, std::size_t elem_len,
+    CFI_rank_t rank, const CFI_index_t extents[]) {
+  // CFI_establish reqs from F2018 section 18.5.5
+  int retCode =
+      CFI_establish(dv, base_addr, attribute, type, elem_len, rank, extents);
+  Descriptor *res = reinterpret_cast<Descriptor *>(dv);
+  if (retCode == CFI_SUCCESS) {
+    res->Check();
+    MATCH((attribute == CFI_attribute_pointer), res->IsPointer());
+    MATCH((attribute == CFI_attribute_allocatable), res->IsAllocatable());
+    MATCH(rank, res->rank());
+    MATCH(reinterpret_cast<std::intptr_t>(dv->base_addr),
+        reinterpret_cast<std::intptr_t>(base_addr));
+    if (base_addr != nullptr) {
+      MATCH(true, res->IsContiguous());
+      for (int i{0}; i < rank; ++i) {
+        MATCH(extents[i], res->GetDimension(i).Extent());
+      }
+    }
+    if (attribute == CFI_attribute_allocatable) {
+      MATCH(res->IsAllocated(), false);
+    }
+    if (attribute == CFI_attribute_pointer) {
+      if (base_addr != nullptr) {
+        for (int i{0}; i < rank; ++i) {
+          MATCH(0, res->GetDimension(i).LowerBound());
+        }
+      }
+    }
+    if (type == CFI_type_struct || type == CFI_type_char ||
+        type == CFI_type_other) {
+      MATCH(elem_len, res->ElementBytes());
+    }
+  }
+  return retCode;
+}
+
+static void AddNoiseToCdesc(CFI_cdesc_t *dv, CFI_rank_t rank) {
+  static int trap;
+  dv->rank = 16;
+  dv->base_addr = reinterpret_cast<void *>(&trap);
+  dv->elem_len = 320;
+  dv->type = CFI_type_struct;
+  dv->attribute = CFI_attribute_pointer;
+  for (int i{0}; i < rank; i++) {
+    dv->dim[i].extent = -42;
+    dv->dim[i].lower_bound = -42;
+    dv->dim[i].sm = -42;
+  }
+}
+
+#ifdef VERBOSE
+static void DumpTestWorld(void *bAddr, CFI_attribute_t attr, CFI_type_t ty,
+    std::size_t eLen, CFI_rank_t rank, CFI_index_t *eAddr) {
+  std::cout << " base_addr: " << std::hex
+            << reinterpret_cast<std::intptr_t>(bAddr)
+            << " attribute: " << static_cast<int>(attr) << std::dec
+            << " type: " << static_cast<int>(ty) << " elem_len: " << eLen
+            << " rank: " << static_cast<int>(rank) << " extent: " << std::hex
+            << reinterpret_cast<std::intptr_t>(eAddr) << std::endl
+            << std::dec;
+}
+#endif
+
+int main() {
+  const int rank3d{3};
+  CFI_index_t extents[CFI_MAX_RANK];
+  CFI_CDESC_T(rank3d) dv3darrayStorage;
+  static CFI_CDESC_T(0) dvScalarStorage;
+  CFI_cdesc_t *dv_3darray{reinterpret_cast<CFI_cdesc_t *>(&dv3darrayStorage)};
+  for (int i{0}; i < CFI_MAX_RANK; ++i) {
+    extents[i] = i + 66;
+  }
+
+  // Test CFI_CDESC_T macro defined in section 18.5.4 of F2018 standard
+  // CFI_CDESC_T must give storage that is:
+  // unqualified
+  MATCH(std::is_const<decltype(dv3darrayStorage)>::value, false);
+  MATCH(std::is_volatile<decltype(dv3darrayStorage)>::value, false);
+  // suitable in size
+  MATCH(sizeof(decltype(dv3darrayStorage)),
+      Descriptor::SizeInBytes(rank3d, false));
+  MATCH(sizeof(decltype(dvScalarStorage)), Descriptor::SizeInBytes(0, false));
+  // suitable in alignment
+  MATCH(reinterpret_cast<std::uintptr_t>(&dv3darrayStorage) &
+          (alignof(CFI_cdesc_t) - 1),
+      0);
+  MATCH(reinterpret_cast<std::uintptr_t>(&dvScalarStorage) &
+          (alignof(CFI_cdesc_t) - 1),
+      0);
+
+  // Testing CFI_establish definied in section 18.5.5
+  CFI_CDESC_T(CFI_MAX_RANK) dv_storage;
+  CFI_cdesc_t *dv{reinterpret_cast<CFI_cdesc_t *>(&dv_storage)};
+  int retCode{CFI_INVALID_DESCRIPTOR};
+  static char base;
+  void *dummyAddr = reinterpret_cast<void *>(&base);
+  // Define test space
+  CFI_attribute_t attrCases[]{
+      CFI_attribute_pointer, CFI_attribute_allocatable, CFI_attribute_other};
+  CFI_type_t typeCases[]{CFI_type_int, CFI_type_struct, CFI_type_double,
+      CFI_type_char, CFI_type_other, CFI_type_struct + 1};
+  CFI_index_t *extentCases[]{extents, static_cast<CFI_index_t *>(nullptr)};
+  void *baseAddrCases[]{dummyAddr, static_cast<void *>(nullptr)};
+  CFI_rank_t rankCases[]{0, 1, CFI_MAX_RANK, CFI_MAX_RANK + 1};
+  std::size_t lenCases[]{0, 42};
+
+  for (CFI_attribute_t attribute : attrCases) {
+    for (void *base_addr : baseAddrCases) {
+      for (CFI_index_t *extent : extentCases) {
+        for (CFI_rank_t rank : rankCases) {
+          for (CFI_type_t type : typeCases) {
+            for (size_t elem_len : lenCases) {
+#ifdef VERBOSE
+              DumpTestWorld(base_addr, attribute, type, elem_len, rank, extent);
+#endif
+              AddNoiseToCdesc(dv, CFI_MAX_RANK);
+              retCode = check_CFI_establish(
+                  dv, base_addr, attribute, type, elem_len, rank, extent);
+              // Combination of args forbidden by the standard:
+              int numErr{0};
+              int expectedRetCode{CFI_SUCCESS};
+              if (base_addr != nullptr &&
+                  attribute == CFI_attribute_allocatable) {
+                ++numErr;
+                expectedRetCode = CFI_ERROR_BASE_ADDR_NOT_NULL;
+              }
+              if (rank < 0 || rank > CFI_MAX_RANK) {
+                ++numErr;
+                expectedRetCode = CFI_INVALID_RANK;
+              }
+              if (type < 0 || type > CFI_type_struct) {
+                ++numErr;
+                expectedRetCode = CFI_INVALID_TYPE;
+              }
+
+              if ((type == CFI_type_struct || type == CFI_type_char ||
+                      type == CFI_type_other) &&
+                  elem_len <= 0) {
+                ++numErr;
+                expectedRetCode = CFI_INVALID_ELEM_LEN;
+              }
+              if (rank > 0 && base_addr != nullptr && extent == nullptr) {
+                ++numErr;
+                expectedRetCode = CFI_INVALID_EXTENT;
+              }
+              if (numErr > 1) {
+                MATCH(true, retCode != CFI_SUCCESS);
+              } else {
+                MATCH(retCode, expectedRetCode);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  // If base_addr is null, extents shall be ignored even if rank !=0
+  AddNoiseToCdesc(dv_3darray, rank3d);  // => dv_3darray->dim[2].extent = -42
+  retCode = check_CFI_establish(dv_3darray, nullptr, CFI_attribute_other,
+      CFI_type_int, 4, rank3d, extents);
+  MATCH(false,
+      dv_3darray->dim[2].extent == 2 + 66);  // extents was read
+
+  // TODO: test CFI_address
+  // TODO: test CFI_allocate
+  // TODO: test CFI_deallocate
+  // TODO: test CFI_establish
+  // TODO: test CFI_is_contiguous
+  // TODO: test CFI_section
+  // TODO: test CFI_select_part
+  // TODO: test CFI_setpointer
+  return testing::Complete();
+}