jpenix-quic updated this revision to Diff 449875.
jpenix-quic added a comment.
Herald added subscribers: bzcheeseman, sdasgup3, wenzhicui, wrengr, cota, 
teijeong, rdzhabarov, tatianashp, msifontes, jurahul, Kayjukh, grosul1, 
Joonsoo, stephenneuendorffer, liufengdb, aartbik, mgester, arpith-jacob, 
nicolasvasilache, antiagainst, shauheen, rriddle.

Attempted to address comments suggesting a different approach for the 
implementation. Rather than add a call to a new set_convert() runtime function, 
create a list of environment variable defaults that is passed into and set by 
the runtime via a "known" extern data structure. Also rebased.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130513/new/

https://reviews.llvm.org/D130513

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Flang.cpp
  flang/examples/external-hello.cpp
  flang/include/flang/Frontend/FrontendOptions.h
  flang/include/flang/Lower/Bridge.h
  flang/include/flang/Lower/Runtime.h
  flang/include/flang/Optimizer/Builder/Runtime/EnvironmentDefaults.h
  flang/include/flang/Optimizer/Support/InternalNames.h
  flang/include/flang/Runtime/environment-defaults.h
  flang/include/flang/Runtime/main.h
  flang/lib/Frontend/CompilerInvocation.cpp
  flang/lib/Frontend/FrontendActions.cpp
  flang/lib/Lower/Bridge.cpp
  flang/lib/Optimizer/Builder/CMakeLists.txt
  flang/lib/Optimizer/Builder/Runtime/EnvironmentDefaults.cpp
  flang/lib/Optimizer/Support/InternalNames.cpp
  flang/runtime/FortranMain/Fortran_main.c
  flang/runtime/environment-default-list.h
  flang/runtime/environment.cpp
  flang/runtime/environment.h
  flang/runtime/main.cpp
  flang/test/Driver/convert.f90
  flang/test/Driver/driver-help-hidden.f90
  flang/test/Driver/driver-help.f90
  flang/test/Driver/emit-mlir.f90
  flang/test/Driver/frontend-forwarding.f90
  flang/test/Lower/convert.f90
  flang/test/Lower/environment-defaults.f90
  flang/test/Runtime/no-cpp-dep.c
  flang/tools/bbc/bbc.cpp
  flang/unittests/Runtime/CommandTest.cpp
  flang/unittests/Runtime/Stop.cpp

Index: flang/unittests/Runtime/Stop.cpp
===================================================================
--- flang/unittests/Runtime/Stop.cpp
+++ flang/unittests/Runtime/Stop.cpp
@@ -26,7 +26,8 @@
 
 TEST(TestProgramEnd, StopTestNoStopMessage) {
   putenv(const_cast<char *>("NO_STOP_MESSAGE=1"));
-  Fortran::runtime::executionEnvironment.Configure(0, nullptr, nullptr);
+  Fortran::runtime::executionEnvironment.Configure(0, nullptr, nullptr,
+                                                   nullptr);
   EXPECT_EXIT(
       RTNAME(StopStatement)(), testing::ExitedWithCode(EXIT_SUCCESS), "");
 }
@@ -52,7 +53,8 @@
 
 TEST(TestProgramEnd, NoStopMessageTest) {
   putenv(const_cast<char *>("NO_STOP_MESSAGE=1"));
-  Fortran::runtime::executionEnvironment.Configure(0, nullptr, nullptr);
+  Fortran::runtime::executionEnvironment.Configure(0, nullptr, nullptr,
+                                                   nullptr);
   static const char *message{"bye bye"};
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
                   /*isErrorStop=*/false, /*quiet=*/false),
Index: flang/unittests/Runtime/CommandTest.cpp
===================================================================
--- flang/unittests/Runtime/CommandTest.cpp
+++ flang/unittests/Runtime/CommandTest.cpp
@@ -49,7 +49,7 @@
 class CommandFixture : public ::testing::Test {
 protected:
   CommandFixture(int argc, const char *argv[]) {
-    RTNAME(ProgramStart)(argc, argv, {});
+    RTNAME(ProgramStart)(argc, argv, {}, {});
   }
 
   std::string GetPaddedStr(const char *text, std::size_t len) const {
Index: flang/tools/bbc/bbc.cpp
===================================================================
--- flang/tools/bbc/bbc.cpp
+++ flang/tools/bbc/bbc.cpp
@@ -220,7 +220,7 @@
   auto burnside = Fortran::lower::LoweringBridge::create(
       ctx, defKinds, semanticsContext.intrinsics(),
       semanticsContext.targetCharacteristics(), parsing.allCooked(), "",
-      kindMap);
+      kindMap, {});
   burnside.lower(parseTree, semanticsContext);
   mlir::ModuleOp mlirModule = burnside.getModule();
   std::error_code ec;
Index: flang/test/Runtime/no-cpp-dep.c
===================================================================
--- flang/test/Runtime/no-cpp-dep.c
+++ flang/test/Runtime/no-cpp-dep.c
@@ -16,18 +16,20 @@
 we're testing. We can't include any headers directly since they likely contain
 C++ code that would explode here.
 */
+struct EnvironmentDefaultList;
 struct Descriptor;
 
 double RTNAME(CpuTime)();
 
-void RTNAME(ProgramStart)(int, const char *[], const char *[]);
+void RTNAME(ProgramStart)(int, const char *[], const char *[],
+                          const struct EnvironmentDefaultList *);
 int32_t RTNAME(ArgumentCount)();
 int32_t RTNAME(GetCommandArgument)(int32_t, const struct Descriptor *,
     const struct Descriptor *, const struct Descriptor *);
 
 int main() {
   double x = RTNAME(CpuTime)();
-  RTNAME(ProgramStart)(0, 0, 0);
+  RTNAME(ProgramStart)(0, 0, 0, 0);
   int32_t c = RTNAME(ArgumentCount)();
   int32_t v = RTNAME(GetCommandArgument)(0, 0, 0, 0);
   return x + c + v;
Index: flang/test/Lower/environment-defaults.f90
===================================================================
--- /dev/null
+++ flang/test/Lower/environment-defaults.f90
@@ -0,0 +1,12 @@
+! RUN: bbc -emit-fir -o - %s | FileCheck %s
+
+program test
+  continue
+end
+
+! Test that a null pointer is generated for environment defaults if nothing is specified
+
+! CHECK: fir.global @_QQEnvironmentDefaults constant : !fir.ref<tuple<i64, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>> {
+! CHECK: %0 = fir.zero_bits !fir.ref<tuple<i64, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
+! CHECK: fir.has_value %0 : !fir.ref<tuple<i64, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
+! CHECK: }
Index: flang/test/Lower/convert.f90
===================================================================
--- /dev/null
+++ flang/test/Lower/convert.f90
@@ -0,0 +1,41 @@
+! RUN: %flang_fc1 -emit-fir -fconvert=big-endian %s -o - | FileCheck %s
+
+program test
+  continue
+end
+
+! Try to test that -fconvert=<value> flag results in a environment default list
+! with the FORT_CONVERT option correctly specified.
+
+! CHECK: fir.global linkonce @_QQEnvironmentDefaults.items constant : !fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>> {
+! CHECK:   %0 = fir.undefined !fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>
+! CHECK:   %1 = fir.address_of([[fc:.*]]) : !fir.ref<!fir.char<1,13>>
+! CHECK:   %c13 = arith.constant 13 : index
+! CHECK:   %2 = fir.convert %1 : (!fir.ref<!fir.char<1,13>>) -> !fir.ref<i8>
+! CHECK:   %3 = fir.insert_value %0, %2, [0 : index, 0 : index] : (!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>, !fir.ref<i8>) -> !fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>
+! CHECK:   %4 = fir.address_of([[be:.*]]) : !fir.ref<!fir.char<1,11>>
+! CHECK:   %c11 = arith.constant 11 : index
+! CHECK:   %5 = fir.convert %4 : (!fir.ref<!fir.char<1,11>>) -> !fir.ref<i8>
+! CHECK:   %6 = fir.insert_value %3, %5, [0 : index, 1 : index] : (!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>, !fir.ref<i8>) -> !fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>
+! CHECK:   fir.has_value %6 : !fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>
+! CHECK: }
+! CHECK: fir.global linkonce [[fc]] constant : !fir.char<1,13> {
+! CHECK:   %0 = fir.string_lit "FORT_CONVERT\00"(13) : !fir.char<1,13>
+! CHECK:   fir.has_value %0 : !fir.char<1,13>
+! CHECK: }
+! CHECK: fir.global linkonce [[be]] constant : !fir.char<1,11> {
+! CHECK:   %0 = fir.string_lit "BIG_ENDIAN\00"(11) : !fir.char<1,11>
+! CHECK:   fir.has_value %0 : !fir.char<1,11>
+! CHECK: }
+! CHECK: fir.global linkonce @_QQEnvironmentDefaults.list constant : tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>> {
+! CHECK:   %0 = fir.undefined tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>
+! CHECK:   %c1_i64 = arith.constant 1 : i64
+! CHECK:   %1 = fir.insert_value %0, %c1_i64, [0 : index] : (tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>, i64) -> tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>
+! CHECK:   %2 = fir.address_of(@_QQEnvironmentDefaults.items) : !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>
+! CHECK:   %3 = fir.insert_value %1, %2, [1 : index] : (tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>) -> tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>
+! CHECK:   fir.has_value %3 : tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>
+! CHECK: }
+! CHECK: fir.global @_QQEnvironmentDefaults constant : !fir.ref<tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>> {
+! CHECK:   %0 = fir.address_of(@_QQEnvironmentDefaults.list) : !fir.ref<tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
+! CHECK:   fir.has_value %0 : !fir.ref<tuple<i64, !fir.ref<!fir.array<1xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
+! CHECK: }
Index: flang/test/Driver/frontend-forwarding.f90
===================================================================
--- flang/test/Driver/frontend-forwarding.f90
+++ flang/test/Driver/frontend-forwarding.f90
@@ -7,6 +7,7 @@
 ! RUN:     -fdefault-integer-8 \
 ! RUN:     -fdefault-real-8 \
 ! RUN:     -flarge-sizes \
+! RUN:     -fconvert=little-endian \
 ! RUN:     -mllvm -print-before-all\
 ! RUN:     -P \
 ! RUN:   | FileCheck %s
@@ -17,4 +18,5 @@
 ! CHECK: "-fdefault-integer-8"
 ! CHECK: "-fdefault-real-8"
 ! CHECK: "-flarge-sizes"
+! CHECK: "-fconvert=little-endian"
 ! CHECK:  "-mllvm" "-print-before-all"
Index: flang/test/Driver/emit-mlir.f90
===================================================================
--- flang/test/Driver/emit-mlir.f90
+++ flang/test/Driver/emit-mlir.f90
@@ -13,6 +13,10 @@
 ! CHECK-LABEL: func @_QQmain() {
 ! CHECK-NEXT:  return
 ! CHECK-NEXT: }
+! CHECK-NEXT: fir.global @_QQEnvironmentDefaults constant : !fir.ref<tuple<i64, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>> {
+! CHECK-NEXT: %0 = fir.zero_bits !fir.ref<tuple<i64, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
+! CHECK-NEXT: fir.has_value %0 : !fir.ref<tuple<i64, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
+! CHECK-NEXT: }
 ! CHECK-NEXT: }
 
 end program
Index: flang/test/Driver/driver-help.f90
===================================================================
--- flang/test/Driver/driver-help.f90
+++ flang/test/Driver/driver-help.f90
@@ -24,6 +24,7 @@
 ! HELP-NEXT: Enable the old style PARAMETER statement
 ! HELP-NEXT: -fbackslash            Specify that backslash in string introduces an escape character
 ! HELP-NEXT: -fcolor-diagnostics    Enable colors in diagnostics
+! HELP-NEXT: -fconvert=<value>       Set endian conversion of data for unformatted files
 ! HELP-NEXT: -fdefault-double-8     Set the default double precision kind to an 8 byte wide type
 ! HELP-NEXT: -fdefault-integer-8    Set the default integer kind to an 8 byte wide type
 ! HELP-NEXT: -fdefault-real-8       Set the default real kind to an 8 byte wide type
@@ -78,6 +79,7 @@
 ! HELP-FC1-NEXT: Enable the old style PARAMETER statement
 ! HELP-FC1-NEXT: -fbackslash            Specify that backslash in string introduces an escape character
 ! HELP-FC1-NEXT: -fcolor-diagnostics     Enable colors in diagnostics
+! HELP-FC1-NEXT: -fconvert=<value>       Set endian conversion of data for unformatted files
 ! HELP-FC1-NEXT: -fdebug-dump-all       Dump symbols and the parse tree after the semantic checks
 ! HELP-FC1-NEXT: -fdebug-dump-parse-tree-no-sema
 ! HELP-FC1-NEXT:                        Dump the parse tree (skips the semantic checks)
Index: flang/test/Driver/driver-help-hidden.f90
===================================================================
--- flang/test/Driver/driver-help-hidden.f90
+++ flang/test/Driver/driver-help-hidden.f90
@@ -24,6 +24,7 @@
 ! CHECK-NEXT: Enable the old style PARAMETER statement
 ! CHECK-NEXT: -fbackslash            Specify that backslash in string introduces an escape character
 ! CHECK-NEXT: -fcolor-diagnostics    Enable colors in diagnostics
+! CHECK-NEXT: -fconvert=<value>       Set endian conversion of data for unformatted files
 ! CHECK-NEXT: -fdefault-double-8     Set the default double precision kind to an 8 byte wide type
 ! CHECK-NEXT: -fdefault-integer-8    Set the default integer kind to an 8 byte wide type
 ! CHECK-NEXT: -fdefault-real-8       Set the default real kind to an 8 byte wide type
Index: flang/test/Driver/convert.f90
===================================================================
--- /dev/null
+++ flang/test/Driver/convert.f90
@@ -0,0 +1,13 @@
+! Ensure argument -fconvert=<value> works as expected.
+
+!--------------------------
+! FLANG DRIVER (flang)
+!--------------------------
+! RUN: not %flang -fconvert=foobar %s  2>&1 | FileCheck %s --check-prefix=WRONG
+
+!!-----------------------------------------
+! FRONTEND FLANG DRIVER (flang-new -fc1)
+!-----------------------------------------
+! RUN: not %flang_fc1 -fconvert=foobar %s  2>&1 | FileCheck %s --check-prefix=WRONG
+
+! WRONG: error: invalid value 'foobar' in '-fconvert=foobar'
Index: flang/runtime/main.cpp
===================================================================
--- flang/runtime/main.cpp
+++ flang/runtime/main.cpp
@@ -9,6 +9,7 @@
 #include "flang/Runtime/main.h"
 #include "environment.h"
 #include "terminator.h"
+#include <cerrno>
 #include <cfenv>
 #include <cstdio>
 #include <cstdlib>
@@ -27,9 +28,11 @@
 }
 
 extern "C" {
-void RTNAME(ProgramStart)(int argc, const char *argv[], const char *envp[]) {
+void RTNAME(ProgramStart)(int argc, const char *argv[], const char *envp[],
+                          const EnvironmentDefaultList *envDefaults) {
   std::atexit(Fortran::runtime::NotifyOtherImagesOfNormalEnd);
-  Fortran::runtime::executionEnvironment.Configure(argc, argv, envp);
+  Fortran::runtime::executionEnvironment.Configure(argc, argv, envp,
+                                                   envDefaults);
   ConfigureFloatingPoint();
   // I/O is initialized on demand so that it works for non-Fortran main().
 }
Index: flang/runtime/environment.h
===================================================================
--- flang/runtime/environment.h
+++ flang/runtime/environment.h
@@ -12,6 +12,8 @@
 #include "flang/Decimal/decimal.h"
 #include <optional>
 
+struct EnvironmentDefaultList;
+
 namespace Fortran::runtime {
 
 class Terminator;
@@ -31,13 +33,14 @@
 
 struct ExecutionEnvironment {
   constexpr ExecutionEnvironment(){};
-  void Configure(int argc, const char *argv[], const char *envp[]);
+  void Configure(int argc, const char *argv[], const char *envp[],
+                 const EnvironmentDefaultList *envDefaults);
   const char *GetEnv(
       const char *name, std::size_t name_length, const Terminator &terminator);
 
   int argc{0};
   const char **argv{nullptr};
-  const char **envp{nullptr};
+  char **envp{nullptr};
 
   int listDirectedOutputLineLengthLimit{79}; // FORT_FMT_RECL
   enum decimal::FortranRounding defaultOutputRoundingMode{
Index: flang/runtime/environment.cpp
===================================================================
--- flang/runtime/environment.cpp
+++ flang/runtime/environment.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "environment.h"
+#include "environment-default-list.h"
 #include "memory.h"
 #include "tools.h"
 #include <cstdio>
@@ -14,10 +15,27 @@
 #include <cstring>
 #include <limits>
 
+extern char **environ;
+
 namespace Fortran::runtime {
 
 ExecutionEnvironment executionEnvironment;
 
+static void SetEnvironmentDefaults(const EnvironmentDefaultList *envDefaults) {
+  if (!envDefaults) {
+    return;
+  }
+
+  for (std::size_t itemIndex = 0; itemIndex < envDefaults->numItems;
+       ++itemIndex) {
+    if (setenv(envDefaults->item[itemIndex].name,
+               envDefaults->item[itemIndex].value, 0) == -1) {
+      Fortran::runtime::Terminator{__FILE__, __LINE__}.Crash(
+          std::strerror(errno));
+    }
+  }
+}
+
 std::optional<Convert> GetConvertFromString(const char *x, std::size_t n) {
   static const char *keywords[]{
       "UNKNOWN", "NATIVE", "LITTLE_ENDIAN", "BIG_ENDIAN", "SWAP", nullptr};
@@ -38,10 +56,12 @@
 }
 
 void ExecutionEnvironment::Configure(
-    int ac, const char *av[], const char *env[]) {
+    int ac, const char *av[], const char *env[],
+    const EnvironmentDefaultList *envDefaults) {
   argc = ac;
   argv = av;
-  envp = env;
+  SetEnvironmentDefaults(envDefaults);
+  envp = environ;
   listDirectedOutputLineLengthLimit = 79; // PGI default
   defaultOutputRoundingMode =
       decimal::FortranRounding::RoundNearest; // RP(==RN)
Index: flang/runtime/environment-default-list.h
===================================================================
--- /dev/null
+++ flang/runtime/environment-default-list.h
@@ -0,0 +1,39 @@
+//===-- Runtime/environment-default-list.h --------------------------------===//
+//
+// 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_RUNTIME_ENVIRONMENT_DEFAULT_LIST_H_
+#define FORTRAN_RUNTIME_ENVIRONMENT_DEFAULT_LIST_H_
+
+// Try to maintain C compatibility to make it easier to both define environment
+// defaults in non-Fortran main programs as well as pass through the environment
+// default list in C code.
+#include "flang/Runtime/c-or-cpp.h"
+#ifdef __cplusplus
+#include <cstddef>
+#else
+#include <stddef.h>
+#endif
+
+// Default values for environment variables are packaged by lowering into an
+// instance of this class to be read and set by the runtime.
+FORTRAN_EXTERN_C_BEGIN
+struct EnvironmentDefaultList {
+  struct Item {
+    const char *name;
+    const char *value;
+  };
+#ifdef __cplusplus
+  std::size_t numItems;
+#else
+  size_t numItems;
+#endif
+  const Item *item;
+};
+FORTRAN_EXTERN_C_END
+
+#endif // FORTRAN_RUNTIME_ENVIRONMENT_DEFAULT_LIST_H_
Index: flang/runtime/FortranMain/Fortran_main.c
===================================================================
--- flang/runtime/FortranMain/Fortran_main.c
+++ flang/runtime/FortranMain/Fortran_main.c
@@ -12,9 +12,11 @@
 /* main entry into PROGRAM */
 void _QQmain(void);
 
+extern const struct EnvironmentDefaultList *_QQEnvironmentDefaults;
+
 /* C main stub */
 int main(int argc, const char *argv[], const char *envp[]) {
-  RTNAME(ProgramStart)(argc, argv, envp);
+  RTNAME(ProgramStart)(argc, argv, envp, _QQEnvironmentDefaults);
   _QQmain();
   RTNAME(ProgramEndStatement)();
   return 0;
Index: flang/lib/Optimizer/Support/InternalNames.cpp
===================================================================
--- flang/lib/Optimizer/Support/InternalNames.cpp
+++ flang/lib/Optimizer/Support/InternalNames.cpp
@@ -220,6 +220,10 @@
   return "_QQmain";
 }
 
+llvm::StringRef fir::NameUniquer::doEnvironmentDefaultList() {
+  return "_QQEnvironmentDefaults";
+}
+
 std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName>
 fir::NameUniquer::deconstruct(llvm::StringRef uniq) {
   if (uniq.startswith("_Q")) {
Index: flang/lib/Optimizer/Builder/Runtime/EnvironmentDefaults.cpp
===================================================================
--- /dev/null
+++ flang/lib/Optimizer/Builder/Runtime/EnvironmentDefaults.cpp
@@ -0,0 +1,108 @@
+//===-- EnvironmentDefaults.cpp -------------------------------------------===//
+//
+// 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 "flang/Optimizer/Builder/Runtime/EnvironmentDefaults.h"
+#include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Support/InternalNames.h"
+#include "flang/Runtime/environment-defaults.h"
+
+void fir::runtime::genEnvironmentDefaults(
+    fir::FirOpBuilder &builder, mlir::Location loc,
+    const std::vector<Fortran::runtime::EnvironmentDefault> &envDefaults) {
+  std::string envDefaultListPtrName =
+      fir::NameUniquer::doEnvironmentDefaultList().str();
+  auto envDefaultListPtr = builder.getNamedGlobal(envDefaultListPtrName);
+  if (envDefaultListPtr)
+    return;
+
+  mlir::MLIRContext *context = builder.getContext();
+  mlir::StringAttr linkOnce = builder.createLinkOnceLinkage();
+  mlir::IndexType idxTy = builder.getIndexType();
+  mlir::IntegerType sizeTy = builder.getIntegerType(8 * sizeof(std::size_t));
+  fir::ReferenceType charRefTy =
+      fir::ReferenceType::get(builder.getIntegerType(8));
+  fir::SequenceType itemListTy = fir::SequenceType::get(
+      envDefaults.size(),
+      mlir::TupleType::get(context, {charRefTy, charRefTy}));
+  mlir::TupleType envDefaultListTy = mlir::TupleType::get(
+      context, {sizeTy, fir::ReferenceType::get(itemListTy)});
+  fir::ReferenceType envDefaultListRefTy =
+      fir::ReferenceType::get(envDefaultListTy);
+  mlir::IntegerAttr zero = builder.getIntegerAttr(idxTy, 0);
+  mlir::IntegerAttr one = builder.getIntegerAttr(idxTy, 1);
+
+  // If no defaults were specified, initialize with a null pointer.
+  if (envDefaults.empty()) {
+    builder.createGlobalConstant(
+        loc, envDefaultListRefTy, envDefaultListPtrName,
+        [&](fir::FirOpBuilder &builder) {
+          auto nullVal = builder.createNullConstant(loc, envDefaultListRefTy);
+          builder.create<fir::HasValueOp>(loc, nullVal);
+        });
+    return;
+  }
+
+  // Create the Item list.
+  std::string itemListName = envDefaultListPtrName + ".items";
+  auto listBuilder = [&](fir::FirOpBuilder &builder) {
+    mlir::Value list = builder.create<fir::UndefOp>(loc, itemListTy);
+    llvm::SmallVector<mlir::Attribute, 2> idx = {mlir::Attribute{},
+                                                 mlir::Attribute{}};
+    auto insertStringField = [&](const std::string &s, const auto &idx) {
+      mlir::Value stringAddress = fir::getBase(
+          fir::factory::createStringLiteral(builder, loc, s + '\0'));
+      mlir::Value addr = builder.createConvert(loc, charRefTy, stringAddress);
+      return builder.create<fir::InsertValueOp>(loc, itemListTy, list, addr,
+                                                builder.getArrayAttr(idx));
+    };
+
+    size_t n = 0;
+    for (const Fortran::runtime::EnvironmentDefault &def : envDefaults) {
+      idx[0] = builder.getIntegerAttr(idxTy, n);
+      idx[1] = zero;
+      list = insertStringField(def.varName, idx);
+      idx[1] = one;
+      list = insertStringField(def.defaultValue, idx);
+    }
+    builder.create<fir::HasValueOp>(loc, list);
+  };
+  builder.createGlobalConstant(loc, itemListTy, itemListName, listBuilder,
+                               linkOnce);
+
+  // Define the EnviornmentDefaultList object.
+  auto envDefaultListBuilder = [&](fir::FirOpBuilder &builder) {
+    mlir::Value envDefaultList =
+        builder.create<fir::UndefOp>(loc, envDefaultListTy);
+    mlir::Value numItems =
+        builder.createIntegerConstant(loc, sizeTy, envDefaults.size());
+    envDefaultList = builder.create<fir::InsertValueOp>(
+        loc, envDefaultListTy, envDefaultList, numItems,
+        builder.getArrayAttr(zero));
+    auto itemList = builder.getNamedGlobal(itemListName);
+    assert(itemList && "missing environment default list");
+    auto listAddr = builder.create<fir::AddrOfOp>(loc, itemList.resultType(),
+                                                  itemList.getSymbol());
+    envDefaultList = builder.create<fir::InsertValueOp>(
+        loc, envDefaultListTy, envDefaultList, listAddr,
+        builder.getArrayAttr(one));
+    builder.create<fir::HasValueOp>(loc, envDefaultList);
+  };
+  fir::GlobalOp envDefaultList = builder.createGlobalConstant(
+      loc, envDefaultListTy, envDefaultListPtrName + ".list",
+      envDefaultListBuilder, linkOnce);
+
+  // Define the pointer to the list used by the runtime.
+  builder.createGlobalConstant(
+      loc, envDefaultListRefTy, envDefaultListPtrName,
+      [&](fir::FirOpBuilder &builder) {
+        mlir::Value addr = builder.create<fir::AddrOfOp>(
+            loc, envDefaultList.resultType(), envDefaultList.getSymbol());
+        builder.create<fir::HasValueOp>(loc, addr);
+      });
+}
Index: flang/lib/Optimizer/Builder/CMakeLists.txt
===================================================================
--- flang/lib/Optimizer/Builder/CMakeLists.txt
+++ flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -12,6 +12,7 @@
   Runtime/Character.cpp
   Runtime/Command.cpp
   Runtime/Derived.cpp
+  Runtime/EnvironmentDefaults.cpp
   Runtime/Inquiry.cpp
   Runtime/Numeric.cpp
   Runtime/Ragged.cpp
Index: flang/lib/Lower/Bridge.cpp
===================================================================
--- flang/lib/Lower/Bridge.cpp
+++ flang/lib/Lower/Bridge.cpp
@@ -31,6 +31,7 @@
 #include "flang/Optimizer/Builder/Character.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/Runtime/Character.h"
+#include "flang/Optimizer/Builder/Runtime/EnvironmentDefaults.h"
 #include "flang/Optimizer/Builder/Runtime/Ragged.h"
 #include "flang/Optimizer/Builder/Todo.h"
 #include "flang/Optimizer/Dialect/FIRAttr.h"
@@ -238,6 +239,17 @@
     /// processed.
     createGlobalOutsideOfFunctionLowering(
         [&]() { runtimeTypeInfoConverter.createTypeInfoGlobals(*this); });
+
+    // Create the list of any environment defaults for the runtime to set. The
+    // runtime default list is only created if there is a main program to ensure
+    // it only happens once and to provide consistent results if multiple files
+    // are compiled separately.
+    if (hasMainProgram) {
+      createGlobalOutsideOfFunctionLowering([&]() {
+        fir::runtime::genEnvironmentDefaults(*builder, toLocation(),
+                                             bridge.getEnvironmentDefaults());
+      });
+    }
   }
 
   /// Declare a function.
@@ -2913,6 +2925,8 @@
         TODO(toLocation(), "support for submodules");
       if (Fortran::semantics::IsSeparateModuleProcedureInterface(&procSymbol))
         TODO(toLocation(), "separate module procedure");
+    } else {
+      hasMainProgram = true;
     }
     setCurrentPosition(funit.getStartingSourceLoc());
     for (int entryIndex = 0, last = funit.entryPointList.size();
@@ -3201,6 +3215,7 @@
   Fortran::lower::SymMap localSymbols;
   Fortran::parser::CharBlock currentPosition;
   RuntimeTypeInfoConverter runtimeTypeInfoConverter;
+  bool hasMainProgram = false;
 
   /// WHERE statement/construct mask expression stack.
   Fortran::lower::ImplicitIterSpace implicitIterSpace;
@@ -3243,10 +3258,11 @@
     const Fortran::evaluate::IntrinsicProcTable &intrinsics,
     const Fortran::evaluate::TargetCharacteristics &targetCharacteristics,
     const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple,
-    fir::KindMapping &kindMap)
+    fir::KindMapping &kindMap,
+    const std::vector<Fortran::runtime::EnvironmentDefault> &envDefaults)
     : defaultKinds{defaultKinds}, intrinsics{intrinsics},
       targetCharacteristics{targetCharacteristics}, cooked{&cooked},
-      context{context}, kindMap{kindMap} {
+      context{context}, kindMap{kindMap}, envDefaults{envDefaults} {
   // Register the diagnostic handler.
   context.getDiagEngine().registerHandler([](mlir::Diagnostic &diag) {
     llvm::raw_ostream &os = llvm::errs();
Index: flang/lib/Frontend/FrontendActions.cpp
===================================================================
--- flang/lib/Frontend/FrontendActions.cpp
+++ flang/lib/Frontend/FrontendActions.cpp
@@ -148,7 +148,7 @@
       *mlirCtx, defKinds, ci.getInvocation().getSemanticsContext().intrinsics(),
       ci.getInvocation().getSemanticsContext().targetCharacteristics(),
       ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple,
-      kindMap);
+      kindMap, ci.getInvocation().getFrontendOpts().envDefaults);
 
   // Create a parse tree and lower it to FIR
   Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()};
Index: flang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- flang/lib/Frontend/CompilerInvocation.cpp
+++ flang/lib/Frontend/CompilerInvocation.cpp
@@ -366,6 +366,27 @@
     }
   }
 
+  // Set conversion based on -fconvert=<value>
+  if (const auto *arg =
+          args.getLastArg(clang::driver::options::OPT_fconvert_EQ)) {
+    auto parseConvertArg = [](const char *s) {
+      return llvm::StringSwitch<std::optional<const char *>>(s)
+          .Case("unknown", "UNKNOWN")
+          .Case("native", "NATIVE")
+          .Case("little-endian", "LITTLE_ENDIAN")
+          .Case("big-endian", "BIG_ENDIAN")
+          .Case("swap", "SWAP")
+          .Default(std::nullopt);
+    };
+
+    const char *argValue = arg->getValue();
+    if (auto convert = parseConvertArg(argValue))
+      opts.envDefaults.push_back({"FORT_CONVERT", *convert});
+    else
+      diags.Report(clang::diag::err_drv_invalid_value)
+          << arg->getAsString(args) << argValue;
+  }
+
   // -f{no-}implicit-none
   opts.features.Enable(
       Fortran::common::LanguageFeature::ImplicitNoneTypeAlways,
Index: flang/include/flang/Runtime/main.h
===================================================================
--- flang/include/flang/Runtime/main.h
+++ flang/include/flang/Runtime/main.h
@@ -12,8 +12,11 @@
 #include "flang/Runtime/c-or-cpp.h"
 #include "flang/Runtime/entry-names.h"
 
+struct EnvironmentDefaultList;
+
 FORTRAN_EXTERN_C_BEGIN
-void RTNAME(ProgramStart)(int, const char *[], const char *[]);
+void RTNAME(ProgramStart)(int, const char *[], const char *[],
+                          const struct EnvironmentDefaultList *);
 void RTNAME(ByteswapOption)(void); // -byteswapio
 FORTRAN_EXTERN_C_END
 
Index: flang/include/flang/Runtime/environment-defaults.h
===================================================================
--- /dev/null
+++ flang/include/flang/Runtime/environment-defaults.h
@@ -0,0 +1,23 @@
+//===-- Runtime/environment-defaults.h ------------------------------------===//
+//
+// 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_RUNTIME_ENVIRONMENT_DEFAULTS_H_
+#define FORTRAN_RUNTIME_ENVIRONMENT_DEFAULTS_H_
+
+#include <string>
+
+namespace Fortran::runtime {
+
+struct EnvironmentDefault {
+  std::string varName;
+  std::string defaultValue;
+};
+
+} // namespace Fortran::runtime
+
+#endif // FORTRAN_RUNTIME_ENVIRONMENT_DEFAULTS_H_
Index: flang/include/flang/Optimizer/Support/InternalNames.h
===================================================================
--- flang/include/flang/Optimizer/Support/InternalNames.h
+++ flang/include/flang/Optimizer/Support/InternalNames.h
@@ -122,6 +122,9 @@
   /// Can be overridden with the `--main-entry-name=<name>` option.
   static llvm::StringRef doProgramEntry();
 
+  /// List of environment variable default values (used by the runtime).
+  static llvm::StringRef doEnvironmentDefaultList();
+
   /// Decompose `uniquedName` into the parse name, symbol type, and scope info
   static std::pair<NameKind, DeconstructedName>
   deconstruct(llvm::StringRef uniquedName);
Index: flang/include/flang/Optimizer/Builder/Runtime/EnvironmentDefaults.h
===================================================================
--- /dev/null
+++ flang/include/flang/Optimizer/Builder/Runtime/EnvironmentDefaults.h
@@ -0,0 +1,36 @@
+//===-- EnvironmentDefaults.h ---------------------------------------------===//
+//
+// 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_OPTIMIZER_BUILDER_RUNTIME_ENVIRONMENTDEFAULTS_H
+#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ENVIRONMENTDEFAULTS_H
+
+#include <vector>
+
+namespace fir {
+class FirOpBuilder;
+} // namespace fir
+
+namespace mlir {
+class Location;
+} // namespace mlir
+
+namespace Fortran::runtime {
+struct EnvironmentDefault;
+} // namespace Fortran::runtime
+
+namespace fir::runtime {
+
+/// Create the list of environment variable defaults for the runtime to set. The
+/// form of the generated list is defined in the runtime header file
+/// environment-default-list.h
+void genEnvironmentDefaults(
+    fir::FirOpBuilder &builder, mlir::Location loc,
+    const std::vector<Fortran::runtime::EnvironmentDefault> &envDefaults);
+
+} // namespace fir::runtime
+#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ENVIRONMENTDEFAULTS_H
Index: flang/include/flang/Lower/Runtime.h
===================================================================
--- flang/include/flang/Lower/Runtime.h
+++ flang/include/flang/Lower/Runtime.h
@@ -46,6 +46,10 @@
 struct UnlockStmt;
 } // namespace parser
 
+namespace runtime {
+struct EnvironmentDefault;
+} // namespace runtime
+
 namespace lower {
 
 class AbstractConverter;
Index: flang/include/flang/Lower/Bridge.h
===================================================================
--- flang/include/flang/Lower/Bridge.h
+++ flang/include/flang/Lower/Bridge.h
@@ -17,6 +17,7 @@
 #include "flang/Lower/AbstractConverter.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Support/KindMapping.h"
+#include "flang/Runtime/environment-defaults.h"
 #include "mlir/IR/BuiltinOps.h"
 
 namespace Fortran {
@@ -52,9 +53,10 @@
          const Fortran::evaluate::IntrinsicProcTable &intrinsics,
          const Fortran::evaluate::TargetCharacteristics &targetCharacteristics,
          const Fortran::parser::AllCookedSources &allCooked,
-         llvm::StringRef triple, fir::KindMapping &kindMap) {
+         llvm::StringRef triple, fir::KindMapping &kindMap,
+         const std::vector<Fortran::runtime::EnvironmentDefault> &envDefaults) {
     return LoweringBridge(ctx, defaultKinds, intrinsics, targetCharacteristics,
-                          allCooked, triple, kindMap);
+                          allCooked, triple, kindMap, envDefaults);
   }
 
   //===--------------------------------------------------------------------===//
@@ -83,6 +85,11 @@
   /// Get the kind map.
   const fir::KindMapping &getKindMap() const { return kindMap; }
 
+  const std::vector<Fortran::runtime::EnvironmentDefault> &
+  getEnvironmentDefaults() const {
+    return envDefaults;
+  }
+
   /// Create a folding context. Careful: this is very expensive.
   Fortran::evaluate::FoldingContext createFoldingContext() const;
 
@@ -107,7 +114,8 @@
       const Fortran::evaluate::IntrinsicProcTable &intrinsics,
       const Fortran::evaluate::TargetCharacteristics &targetCharacteristics,
       const Fortran::parser::AllCookedSources &cooked, llvm::StringRef triple,
-      fir::KindMapping &kindMap);
+      fir::KindMapping &kindMap,
+      const std::vector<Fortran::runtime::EnvironmentDefault> &envDefaults);
   LoweringBridge() = delete;
   LoweringBridge(const LoweringBridge &) = delete;
 
@@ -118,6 +126,7 @@
   mlir::MLIRContext &context;
   std::unique_ptr<mlir::ModuleOp> module;
   fir::KindMapping &kindMap;
+  const std::vector<Fortran::runtime::EnvironmentDefault> &envDefaults;
 };
 
 } // namespace lower
Index: flang/include/flang/Frontend/FrontendOptions.h
===================================================================
--- flang/include/flang/Frontend/FrontendOptions.h
+++ flang/include/flang/Frontend/FrontendOptions.h
@@ -16,6 +16,7 @@
 #include "flang/Common/Fortran-features.h"
 #include "flang/Parser/characters.h"
 #include "flang/Parser/unparse.h"
+#include "flang/Runtime/environment-defaults.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include <cstdint>
@@ -258,6 +259,9 @@
   // The form to process files in, if specified.
   FortranForm fortranForm = FortranForm::Unknown;
 
+  // Default values for environment variables to be set by the runtime.
+  std::vector<Fortran::runtime::EnvironmentDefault> envDefaults;
+
   // The column after which characters are ignored in fixed form lines in the
   // source file.
   int fixedFormColumns = 72;
Index: flang/examples/external-hello.cpp
===================================================================
--- flang/examples/external-hello.cpp
+++ flang/examples/external-hello.cpp
@@ -42,7 +42,7 @@
 }
 
 int main(int argc, const char *argv[], const char *envp[]) {
-  RTNAME(ProgramStart)(argc, argv, envp);
+  RTNAME(ProgramStart)(argc, argv, envp, nullptr);
   output1();
   input1();
   RTNAME(PauseStatement)();
Index: clang/lib/Driver/ToolChains/Flang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Flang.cpp
+++ clang/lib/Driver/ToolChains/Flang.cpp
@@ -55,7 +55,8 @@
   Args.AddAllArgs(CmdArgs,
                   {options::OPT_module_dir, options::OPT_fdebug_module_writer,
                    options::OPT_fintrinsic_modules_path, options::OPT_pedantic,
-                   options::OPT_std_EQ, options::OPT_W_Joined});
+                   options::OPT_std_EQ, options::OPT_W_Joined,
+                   options::OPT_fconvert_EQ});
 }
 
 void Flang::ConstructJob(Compilation &C, const JobAction &JA,
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -4790,7 +4790,6 @@
 def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group<gfortran_Group>;
 def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>;
 def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group<gfortran_Group>;
-def fconvert_EQ : Joined<["-"], "fconvert=">, Group<gfortran_Group>;
 def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>;
 def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>;
 def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>;
@@ -4891,6 +4890,8 @@
   DocBrief<[{Set column after which characters are ignored in typical fixed-form lines in the source
 file}]>;
 def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group<f_Group>, Alias<ffixed_line_length_EQ>;
+def fconvert_EQ : Joined<["-"], "fconvert=">, Group<f_Group>,
+  HelpText<"Set endian conversion of data for unformatted files">;
 def fopenacc : Flag<["-"], "fopenacc">, Group<f_Group>,
   HelpText<"Enable OpenACC">;
 def fdefault_double_8 : Flag<["-"],"fdefault-double-8">, Group<f_Group>,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to