[flang-commits] [flang] df63023 - [flang] GET_COMMAND_ARGUMENT(VALUE) runtime implementation

Diana Picus via flang-commits flang-commits at lists.llvm.org
Tue Sep 28 01:38:00 PDT 2021


Author: Diana Picus
Date: 2021-09-28T08:32:19Z
New Revision: df6302311f88d0fbc666b6277d029aa371039945

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

LOG: [flang] GET_COMMAND_ARGUMENT(VALUE) runtime implementation

Partial implementation for the second entry point for
GET_COMMAND_ARGUMENT. It handles the VALUE and STATUS arguments, and
doesn't touch ERRMSG.

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

Added: 
    

Modified: 
    flang/runtime/command.cpp
    flang/test/Runtime/no-cpp-dep.c
    flang/unittests/Runtime/CommandTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp
index 1a55061749a1c..9dea6e4ca903f 100644
--- a/flang/runtime/command.cpp
+++ b/flang/runtime/command.cpp
@@ -8,6 +8,7 @@
 
 #include "flang/Runtime/command.h"
 #include "environment.h"
+#include "flang/Runtime/descriptor.h"
 #include <limits>
 
 namespace Fortran::runtime {
@@ -20,11 +21,8 @@ std::int32_t RTNAME(ArgumentCount)() {
   return 0;
 }
 
-std::int64_t RTNAME(ArgumentLength)(std::int32_t n) {
-  if (n < 0 || n >= executionEnvironment.argc) {
-    return 0;
-  }
-
+// Returns the length of the \p n'th argument. Assumes \p n is valid.
+static std::int64_t ArgumentLength(std::int32_t n) {
   std::size_t length{std::strlen(executionEnvironment.argv[n])};
   if constexpr (sizeof(std::size_t) <= sizeof(std::int64_t)) {
     return static_cast<std::int64_t>(length);
@@ -34,4 +32,49 @@ std::int64_t RTNAME(ArgumentLength)(std::int32_t n) {
                         : static_cast<std::int64_t>(length);
   }
 }
+
+std::int64_t RTNAME(ArgumentLength)(std::int32_t n) {
+  if (n < 0 || n >= executionEnvironment.argc) {
+    return 0;
+  }
+
+  return ArgumentLength(n);
+}
+
+static bool IsValidCharDescriptor(const Descriptor *value) {
+  return value && value->IsAllocated() &&
+      value->type() == TypeCode(TypeCategory::Character, 1) &&
+      value->rank() == 0;
+}
+
+static void FillWithSpaces(const Descriptor *value) {
+  std::memset(value->OffsetElement(), ' ', value->ElementBytes());
+}
+
+std::int32_t RTNAME(ArgumentValue)(
+    std::int32_t n, const Descriptor *value, const Descriptor *errmsg) {
+  if (IsValidCharDescriptor(value)) {
+    FillWithSpaces(value);
+  }
+
+  if (n < 0 || n >= executionEnvironment.argc) {
+    return 1;
+  }
+
+  if (IsValidCharDescriptor(value)) {
+    std::int64_t argLen{ArgumentLength(n)};
+    if (argLen <= 0) {
+      return 2;
+    }
+
+    std::int64_t toCopy{
+        std::min(argLen, static_cast<std::int64_t>(value->ElementBytes()))};
+    std::strncpy(value->OffsetElement(), executionEnvironment.argv[n], toCopy);
+
+    if (argLen > toCopy) {
+      return -1;
+    }
+  }
+  return 0;
+}
 } // namespace Fortran::runtime

diff  --git a/flang/test/Runtime/no-cpp-dep.c b/flang/test/Runtime/no-cpp-dep.c
index 9970e098c34ff..0f99ccc95e60c 100644
--- a/flang/test/Runtime/no-cpp-dep.c
+++ b/flang/test/Runtime/no-cpp-dep.c
@@ -22,12 +22,15 @@ double RTNAME(CpuTime)();
 
 void RTNAME(ProgramStart)(int, const char *[], const char *[]);
 int32_t RTNAME(ArgumentCount)();
+int32_t RTNAME(ArgumentValue)(
+    int32_t, const struct Descriptor *, const struct Descriptor *);
 int64_t RTNAME(ArgumentLength)(int32_t);
 
 int main() {
   double x = RTNAME(CpuTime)();
   RTNAME(ProgramStart)(0, 0, 0);
   int32_t c = RTNAME(ArgumentCount)();
+  int32_t v = RTNAME(ArgumentValue)(0, 0, 0);
   int32_t l = RTNAME(ArgumentLength)(0);
   return x + c + l;
 }

diff  --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp
index 3841bbe0ed3ba..69c309d61af0d 100644
--- a/flang/unittests/Runtime/CommandTest.cpp
+++ b/flang/unittests/Runtime/CommandTest.cpp
@@ -13,11 +13,55 @@
 
 using namespace Fortran::runtime;
 
+template <std::size_t n = 64>
+static OwningPtr<Descriptor> CreateEmptyCharDescriptor() {
+  OwningPtr<Descriptor> descriptor{Descriptor::Create(
+      sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)};
+  if (descriptor->Allocate() != 0) {
+    return nullptr;
+  }
+  return descriptor;
+}
+
 class CommandFixture : public ::testing::Test {
 protected:
   CommandFixture(int argc, const char *argv[]) {
     RTNAME(ProgramStart)(argc, argv, {});
   }
+
+  std::string GetPaddedStr(const char *text, std::size_t len) const {
+    std::string res{text};
+    assert(res.length() <= len && "No room to pad");
+    res.append(len - res.length(), ' ');
+    return res;
+  }
+
+  void CheckDescriptorEqStr(
+      const Descriptor *value, const std::string &expected) const {
+    EXPECT_EQ(std::strncmp(value->OffsetElement(), expected.c_str(),
+                  value->ElementBytes()),
+        0);
+  }
+
+  void CheckArgumentValue(int n, const char *argv) const {
+    OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
+    ASSERT_NE(value, nullptr);
+
+    std::string expected{GetPaddedStr(argv, value->ElementBytes())};
+
+    EXPECT_EQ(RTNAME(ArgumentValue)(n, value.get(), nullptr), 0);
+    CheckDescriptorEqStr(value.get(), expected);
+  }
+
+  void CheckMissingArgumentValue(int n) const {
+    OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
+    ASSERT_NE(value, nullptr);
+
+    EXPECT_GT(RTNAME(ArgumentValue)(n, value.get(), nullptr), 0);
+
+    std::string spaces(value->ElementBytes(), ' ');
+    CheckDescriptorEqStr(value.get(), spaces);
+  }
 };
 
 static const char *commandOnlyArgv[]{"aProgram"};
@@ -34,6 +78,10 @@ TEST_F(ZeroArguments, ArgumentLength) {
   EXPECT_EQ(0, RTNAME(ArgumentLength)(1));
 }
 
+TEST_F(ZeroArguments, ArgumentValue) {
+  CheckArgumentValue(0, commandOnlyArgv[0]);
+}
+
 static const char *oneArgArgv[]{"aProgram", "anArgumentOfLength20"};
 class OneArgument : public CommandFixture {
 protected:
@@ -49,6 +97,11 @@ TEST_F(OneArgument, ArgumentLength) {
   EXPECT_EQ(0, RTNAME(ArgumentLength)(2));
 }
 
+TEST_F(OneArgument, ArgumentValue) {
+  CheckArgumentValue(0, oneArgArgv[0]);
+  CheckArgumentValue(1, oneArgArgv[1]);
+}
+
 static const char *severalArgsArgv[]{
     "aProgram", "16-char-long-arg", "", "-22-character-long-arg", "o"};
 class SeveralArguments : public CommandFixture {
@@ -71,3 +124,28 @@ TEST_F(SeveralArguments, ArgumentLength) {
   EXPECT_EQ(1, RTNAME(ArgumentLength)(4));
   EXPECT_EQ(0, RTNAME(ArgumentLength)(5));
 }
+
+TEST_F(SeveralArguments, ArgumentValue) {
+  CheckArgumentValue(0, severalArgsArgv[0]);
+  CheckArgumentValue(1, severalArgsArgv[1]);
+  CheckMissingArgumentValue(2);
+  CheckArgumentValue(3, severalArgsArgv[3]);
+  CheckArgumentValue(4, severalArgsArgv[4]);
+}
+
+TEST_F(SeveralArguments, NoArgumentValue) {
+  // Make sure we don't crash if the 'value' and 'error' parameters aren't
+  // passed.
+  EXPECT_EQ(RTNAME(ArgumentValue)(2, nullptr, nullptr), 0);
+  EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, nullptr), 0);
+}
+
+TEST_F(SeveralArguments, ArgumentValueErrors) {
+  CheckMissingArgumentValue(-1);
+  CheckMissingArgumentValue(5);
+
+  OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<15>()};
+  ASSERT_NE(tooShort, nullptr);
+  EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), nullptr), -1);
+  CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]);
+}


        


More information about the flang-commits mailing list