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; def fcheck_EQ : Joined<["-"], "fcheck=">, Group; def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group; -def fconvert_EQ : Joined<["-"], "fconvert=">, Group; def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group; def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group; def finit_character_EQ : Joined<["-"], "finit-character=">, 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, Alias; +def fconvert_EQ : Joined<["-"], "fconvert=">, Group, + HelpText<"Set endian conversion of data for unformatted files">; def fopenacc : Flag<["-"], "fopenacc">, Group, HelpText<"Enable OpenACC">; def fdefault_double_8 : Flag<["-"],"fdefault-double-8">, Group, 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: 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: 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 @@ -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 envDefaults; + // The column after which characters are ignored in fixed form lines in the // source file. int fixedFormColumns = 72; 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 &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 & + 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 &envDefaults); LoweringBridge() = delete; LoweringBridge(const LoweringBridge &) = delete; @@ -118,6 +126,7 @@ mlir::MLIRContext &context; std::unique_ptr module; fir::KindMapping &kindMap; + const std::vector &envDefaults; }; } // namespace lower 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/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 + +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 &envDefaults); + +} // namespace fir::runtime +#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ENVIRONMENTDEFAULTS_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=` 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 deconstruct(llvm::StringRef uniquedName); 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 + +namespace Fortran::runtime { + +struct EnvironmentDefault { + std::string varName; + std::string defaultValue; +}; + +} // namespace Fortran::runtime + +#endif // FORTRAN_RUNTIME_ENVIRONMENT_DEFAULTS_H_ 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/lib/Frontend/CompilerInvocation.cpp =================================================================== --- flang/lib/Frontend/CompilerInvocation.cpp +++ flang/lib/Frontend/CompilerInvocation.cpp @@ -366,6 +366,27 @@ } } + // Set conversion based on -fconvert= + if (const auto *arg = + args.getLastArg(clang::driver::options::OPT_fconvert_EQ)) { + auto parseConvertArg = [](const char *s) { + return llvm::StringSwitch>(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/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/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 &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/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/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 &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(loc, nullVal); + }); + return; + } + + // Create the Item list. + std::string itemListName = envDefaultListPtrName + ".items"; + auto listBuilder = [&](fir::FirOpBuilder &builder) { + mlir::Value list = builder.create(loc, itemListTy); + llvm::SmallVector 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(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(loc, list); + }; + builder.createGlobalConstant(loc, itemListTy, itemListName, listBuilder, + linkOnce); + + // Define the EnviornmentDefaultList object. + auto envDefaultListBuilder = [&](fir::FirOpBuilder &builder) { + mlir::Value envDefaultList = + builder.create(loc, envDefaultListTy); + mlir::Value numItems = + builder.createIntegerConstant(loc, sizeTy, envDefaults.size()); + envDefaultList = builder.create( + loc, envDefaultListTy, envDefaultList, numItems, + builder.getArrayAttr(zero)); + auto itemList = builder.getNamedGlobal(itemListName); + assert(itemList && "missing environment default list"); + auto listAddr = builder.create(loc, itemList.resultType(), + itemList.getSymbol()); + envDefaultList = builder.create( + loc, envDefaultListTy, envDefaultList, listAddr, + builder.getArrayAttr(one)); + builder.create(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( + loc, envDefaultList.resultType(), envDefaultList.getSymbol()); + builder.create(loc, addr); + }); +} 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::deconstruct(llvm::StringRef uniq) { if (uniq.startswith("_Q")) { 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/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 +#else +#include +#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/environment.h =================================================================== --- flang/runtime/environment.h +++ flang/runtime/environment.h @@ -12,6 +12,8 @@ #include "flang/Decimal/decimal.h" #include +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 @@ -14,10 +15,39 @@ #include #include +#ifdef _WIN32 +extern char **_environ; +#else +extern char **environ; +#endif + namespace Fortran::runtime { ExecutionEnvironment executionEnvironment; +static void SetEnvironmentDefaults(const EnvironmentDefaultList *envDefaults) { + if (!envDefaults) { + return; + } + + for (std::size_t itemIndex = 0; itemIndex < envDefaults->numItems; + ++itemIndex) { + const char *name = envDefaults->item[itemIndex].name; + const char *value = envDefaults->item[itemIndex].value; +#ifdef _WIN32 + if (auto *x{std::getenv(name)}) { + continue; + } + if (_putenv_s(name, value) != 0) { +#else + if (setenv(name, value, 0) == -1) { +#endif + Fortran::runtime::Terminator{__FILE__, __LINE__}.Crash( + std::strerror(errno)); + } + } +} + std::optional GetConvertFromString(const char *x, std::size_t n) { static const char *keywords[]{ "UNKNOWN", "NATIVE", "LITTLE_ENDIAN", "BIG_ENDIAN", "SWAP", nullptr}; @@ -37,11 +67,16 @@ } } -void ExecutionEnvironment::Configure( - int ac, const char *av[], const char *env[]) { +void ExecutionEnvironment::Configure(int ac, const char *av[], + const char *env[], const EnvironmentDefaultList *envDefaults) { argc = ac; argv = av; - envp = env; + SetEnvironmentDefaults(envDefaults); +#ifdef _WIN32 + envp = _environ; +#else + envp = environ; +#endif listDirectedOutputLineLengthLimit = 79; // PGI default defaultOutputRoundingMode = decimal::FortranRounding::RoundNearest; // RP(==RN) 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 #include #include #include @@ -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/test/Driver/convert.f90 =================================================================== --- /dev/null +++ flang/test/Driver/convert.f90 @@ -0,0 +1,13 @@ +! Ensure argument -fconvert= 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/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= 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/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= 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= 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/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, !fir.ref>>>>> { +! CHECK-NEXT: %0 = fir.zero_bits !fir.ref, !fir.ref>>>>> +! CHECK-NEXT: fir.has_value %0 : !fir.ref, !fir.ref>>>>> +! CHECK-NEXT: } ! CHECK-NEXT: } end program 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/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= 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>> { +! CHECK: %0 = fir.undefined !fir.array<1xtuple, !fir.ref>> +! CHECK: %1 = fir.address_of([[fc:.*]]) : !fir.ref> +! CHECK: %c13 = arith.constant 13 : index +! CHECK: %2 = fir.convert %1 : (!fir.ref>) -> !fir.ref +! CHECK: %3 = fir.insert_value %0, %2, [0 : index, 0 : index] : (!fir.array<1xtuple, !fir.ref>>, !fir.ref) -> !fir.array<1xtuple, !fir.ref>> +! CHECK: %4 = fir.address_of([[be:.*]]) : !fir.ref> +! CHECK: %c11 = arith.constant 11 : index +! CHECK: %5 = fir.convert %4 : (!fir.ref>) -> !fir.ref +! CHECK: %6 = fir.insert_value %3, %5, [0 : index, 1 : index] : (!fir.array<1xtuple, !fir.ref>>, !fir.ref) -> !fir.array<1xtuple, !fir.ref>> +! CHECK: fir.has_value %6 : !fir.array<1xtuple, !fir.ref>> +! 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, !fir.ref>>>> { +! CHECK: %0 = fir.undefined tuple, !fir.ref>>>> +! CHECK: %c1_i64 = arith.constant 1 : i64 +! CHECK: %1 = fir.insert_value %0, %c1_i64, [0 : index] : (tuple, !fir.ref>>>>, i64) -> tuple, !fir.ref>>>> +! CHECK: %2 = fir.address_of(@_QQEnvironmentDefaults.items) : !fir.ref, !fir.ref>>> +! CHECK: %3 = fir.insert_value %1, %2, [1 : index] : (tuple, !fir.ref>>>>, !fir.ref, !fir.ref>>>) -> tuple, !fir.ref>>>> +! CHECK: fir.has_value %3 : tuple, !fir.ref>>>> +! CHECK: } +! CHECK: fir.global @_QQEnvironmentDefaults constant : !fir.ref, !fir.ref>>>>> { +! CHECK: %0 = fir.address_of(@_QQEnvironmentDefaults.list) : !fir.ref, !fir.ref>>>>> +! CHECK: fir.has_value %0 : !fir.ref, !fir.ref>>>>> +! CHECK: } 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, !fir.ref>>>>> { +! CHECK: %0 = fir.zero_bits !fir.ref, !fir.ref>>>>> +! CHECK: fir.has_value %0 : !fir.ref, !fir.ref>>>>> +! CHECK: } 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/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/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/unittests/Runtime/Stop.cpp =================================================================== --- flang/unittests/Runtime/Stop.cpp +++ flang/unittests/Runtime/Stop.cpp @@ -26,7 +26,8 @@ TEST(TestProgramEnd, StopTestNoStopMessage) { putenv(const_cast("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("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),