mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 07:31:28 +00:00
Flang implementation for COMPILER_VERSION and COMPILER_OPTIONS intrinsics
This revision implements the Fortran intrinsic procedures COMPILER_VERSION and COMPILER_OPTIONS from the iso_fortran_env module. To be able to set the COMPILER_OPTIONS string according to the original compiler driver invocation, a string is passed to the frontend driver using the environment variable FLANG_COMPILER_OPTIONS_STRING, for lack of a better mechanism. Fixes #59233 Reviewed By: awarzynski Differential Revision: https://reviews.llvm.org/D140524
This commit is contained in:
parent
2129cc1b3a
commit
541f5c4a6d
56
flang/include/flang/Common/Version.h
Normal file
56
flang/include/flang/Common/Version.h
Normal file
@ -0,0 +1,56 @@
|
||||
//===- Version.h - Flang Version Number ---------------------*- Fortran -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Defines version macros and version-related utility functions
|
||||
/// for Flang.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FLANG_COMMON_VERSION_H
|
||||
#define LLVM_FLANG_COMMON_VERSION_H
|
||||
|
||||
#include "flang/Version.inc"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace Fortran::common {
|
||||
/// Retrieves the repository path (e.g., Git path) that
|
||||
/// identifies the particular Flang branch, tag, or trunk from which this
|
||||
/// Flang was built.
|
||||
std::string getFlangRepositoryPath();
|
||||
|
||||
/// Retrieves the repository path from which LLVM was built.
|
||||
///
|
||||
/// This supports LLVM residing in a separate repository from flang.
|
||||
std::string getLLVMRepositoryPath();
|
||||
|
||||
/// Retrieves the repository revision number (or identifier) from which
|
||||
/// this Flang was built.
|
||||
std::string getFlangRevision();
|
||||
|
||||
/// Retrieves the repository revision number (or identifier) from which
|
||||
/// LLVM was built.
|
||||
///
|
||||
/// If Flang and LLVM are in the same repository, this returns the same
|
||||
/// string as getFlangRevision.
|
||||
std::string getLLVMRevision();
|
||||
|
||||
/// Retrieves the full repository version that is an amalgamation of
|
||||
/// the information in getFlangRepositoryPath() and getFlangRevision().
|
||||
std::string getFlangFullRepositoryVersion();
|
||||
|
||||
/// Retrieves a string representing the complete flang version,
|
||||
/// which includes the flang version number, the repository version,
|
||||
/// and the vendor tag.
|
||||
std::string getFlangFullVersion();
|
||||
|
||||
/// Like getFlangFullVersion(), but with a custom tool name.
|
||||
std::string getFlangToolFullVersion(llvm::StringRef ToolName);
|
||||
} // namespace Fortran::common
|
||||
|
||||
#endif // LLVM_FLANG_COMMON_VERSION_H
|
@ -75,6 +75,22 @@ public:
|
||||
|
||||
static Rounding defaultRounding;
|
||||
|
||||
const std::string &compilerOptionsString() const {
|
||||
return compilerOptionsString_;
|
||||
};
|
||||
TargetCharacteristics &set_compilerOptionsString(std::string x) {
|
||||
compilerOptionsString_ = x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string &compilerVersionString() const {
|
||||
return compilerVersionString_;
|
||||
};
|
||||
TargetCharacteristics &set_compilerVersionString(std::string x) {
|
||||
compilerVersionString_ = x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int maxKind{32};
|
||||
std::uint8_t byteSize_[common::TypeCategory_enumSize][maxKind]{};
|
||||
@ -87,6 +103,8 @@ private:
|
||||
std::size_t descriptorAlignment_{8};
|
||||
std::size_t maxByteSize_{8 /*at least*/};
|
||||
std::size_t maxAlignment_{8 /*at least*/};
|
||||
std::string compilerOptionsString_;
|
||||
std::string compilerVersionString_;
|
||||
};
|
||||
|
||||
} // namespace Fortran::evaluate
|
||||
|
@ -82,6 +82,11 @@ class CompilerInvocation : public CompilerInvocationBase {
|
||||
/// Options controlling language dialect.
|
||||
Fortran::frontend::LangOptions langOpts;
|
||||
|
||||
// The original invocation of the compiler driver.
|
||||
// This string will be set as the return value from the COMPILER_OPTIONS
|
||||
// intrinsic of iso_fortran_env.
|
||||
std::string allCompilerInvocOpts;
|
||||
|
||||
// Semantics context
|
||||
std::unique_ptr<Fortran::semantics::SemanticsContext> semanticsContext;
|
||||
|
||||
@ -208,7 +213,8 @@ public:
|
||||
/// \param [out] res - The resulting invocation.
|
||||
static bool createFromArgs(CompilerInvocation &res,
|
||||
llvm::ArrayRef<const char *> commandLineArgs,
|
||||
clang::DiagnosticsEngine &diags);
|
||||
clang::DiagnosticsEngine &diags,
|
||||
const char *argv0 = nullptr);
|
||||
|
||||
// Enables the std=f2018 conformance check
|
||||
void setEnableConformanceChecks() { enableConformanceChecks = true; }
|
||||
|
@ -1,9 +1,45 @@
|
||||
find_first_existing_vc_file("${LLVM_MAIN_SRC_DIR}" llvm_vc)
|
||||
find_first_existing_vc_file("${FLANG_SOURCE_DIR}" flang_vc)
|
||||
|
||||
# The VC revision include that we want to generate.
|
||||
set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSVersion.inc")
|
||||
|
||||
set(generate_vcs_version_script "${LLVM_CMAKE_DIR}/GenerateVersionFromVCS.cmake")
|
||||
|
||||
if(llvm_vc AND LLVM_APPEND_VC_REV)
|
||||
set(llvm_source_dir ${LLVM_MAIN_SRC_DIR})
|
||||
endif()
|
||||
if(flang_vc AND LLVM_APPEND_VC_REV)
|
||||
set(flang_source_dir ${FLANG_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
# Create custom target to generate the VC revision include.
|
||||
add_custom_command(OUTPUT "${version_inc}"
|
||||
DEPENDS "${llvm_vc}" "${flang_vc}" "${generate_vcs_version_script}"
|
||||
COMMAND ${CMAKE_COMMAND} "-DNAMES=\"LLVM;FLANG\""
|
||||
"-DLLVM_SOURCE_DIR=${llvm_source_dir}"
|
||||
"-DFLANG_SOURCE_DIR=${flang_source_dir}"
|
||||
"-DHEADER_FILE=${version_inc}"
|
||||
-P "${generate_vcs_version_script}")
|
||||
|
||||
# Mark the generated header as being generated.
|
||||
set_source_files_properties("${version_inc}"
|
||||
PROPERTIES GENERATED TRUE
|
||||
HEADER_FILE_ONLY TRUE)
|
||||
|
||||
if(FLANG_VENDOR)
|
||||
set_source_files_properties(Version.cpp
|
||||
PROPERTIES COMPILE_DEFINITIONS "FLANG_VENDOR=\"${FLANG_VENDOR} \"")
|
||||
endif()
|
||||
|
||||
|
||||
add_flang_library(FortranCommon
|
||||
Fortran.cpp
|
||||
Fortran-features.cpp
|
||||
default-kinds.cpp
|
||||
idioms.cpp
|
||||
Version.cpp
|
||||
${version_inc}
|
||||
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
|
104
flang/lib/Common/Version.cpp
Normal file
104
flang/lib/Common/Version.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
//===- Version.cpp - Flang Version Number -------------------*- Fortran -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines several version-related utility functions for Flang.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Common/Version.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "VCSVersion.inc"
|
||||
|
||||
namespace Fortran::common {
|
||||
|
||||
std::string getFlangRepositoryPath() {
|
||||
#if defined(FLANG_REPOSITORY_STRING)
|
||||
return FLANG_REPOSITORY_STRING;
|
||||
#else
|
||||
#ifdef FLANG_REPOSITORY
|
||||
return FLANG_REPOSITORY;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getLLVMRepositoryPath() {
|
||||
#ifdef LLVM_REPOSITORY
|
||||
return LLVM_REPOSITORY;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getFlangRevision() {
|
||||
#ifdef FLANG_REVISION
|
||||
return FLANG_REVISION;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getLLVMRevision() {
|
||||
#ifdef LLVM_REVISION
|
||||
return LLVM_REVISION;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getFlangFullRepositoryVersion() {
|
||||
std::string buf;
|
||||
llvm::raw_string_ostream OS(buf);
|
||||
std::string Path = getFlangRepositoryPath();
|
||||
std::string Revision = getFlangRevision();
|
||||
if (!Path.empty() || !Revision.empty()) {
|
||||
OS << '(';
|
||||
if (!Path.empty())
|
||||
OS << Path;
|
||||
if (!Revision.empty()) {
|
||||
if (!Path.empty())
|
||||
OS << ' ';
|
||||
OS << Revision;
|
||||
}
|
||||
OS << ')';
|
||||
}
|
||||
// Support LLVM in a separate repository.
|
||||
std::string LLVMRev = getLLVMRevision();
|
||||
if (!LLVMRev.empty() && LLVMRev != Revision) {
|
||||
OS << " (";
|
||||
std::string LLVMRepo = getLLVMRepositoryPath();
|
||||
if (!LLVMRepo.empty())
|
||||
OS << LLVMRepo << ' ';
|
||||
OS << LLVMRev << ')';
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string getFlangFullVersion() { return getFlangToolFullVersion("flang"); }
|
||||
|
||||
std::string getFlangToolFullVersion(llvm::StringRef ToolName) {
|
||||
std::string buf;
|
||||
llvm::raw_string_ostream OS(buf);
|
||||
#ifdef FLANG_VENDOR
|
||||
OS << FLANG_VENDOR;
|
||||
#endif
|
||||
OS << ToolName << " version " FLANG_VERSION_STRING;
|
||||
|
||||
std::string repo = getFlangFullRepositoryVersion();
|
||||
if (!repo.empty()) {
|
||||
OS << " " << repo;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // end namespace Fortran::common
|
@ -118,6 +118,12 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
|
||||
return Expr<T>{Constant<T>{
|
||||
CharacterUtils<KIND>::TRIM(std::get<Scalar<T>>(*scalar))}};
|
||||
}
|
||||
} else if (name == "__builtin_compiler_options") {
|
||||
auto &o = context.targetCharacteristics().compilerOptionsString();
|
||||
return Expr<T>{Constant<T>{StringType(o.begin(), o.end())}};
|
||||
} else if (name == "__builtin_compiler_version") {
|
||||
auto &v = context.targetCharacteristics().compilerVersionString();
|
||||
return Expr<T>{Constant<T>{StringType(v.begin(), v.end())}};
|
||||
}
|
||||
return Expr<T>{std::move(funcRef)};
|
||||
}
|
||||
|
@ -916,6 +916,8 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
||||
{"__builtin_ieee_support_underflow_control",
|
||||
{{"x", AnyReal, Rank::elemental, Optionality::optional}},
|
||||
DefaultLogical},
|
||||
{"__builtin_compiler_options", {}, DefaultChar},
|
||||
{"__builtin_compiler_version", {}, DefaultChar},
|
||||
};
|
||||
|
||||
// TODO: Coarray intrinsic functions
|
||||
@ -2070,6 +2072,12 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
|
||||
resultType = DynamicType{TypeCategory::Logical,
|
||||
defaults.GetDefaultKind(TypeCategory::Logical)};
|
||||
break;
|
||||
case KindCode::defaultCharKind:
|
||||
CHECK(result.categorySet == CharType);
|
||||
CHECK(*category == TypeCategory::Character);
|
||||
resultType = DynamicType{TypeCategory::Character,
|
||||
defaults.GetDefaultKind(TypeCategory::Character)};
|
||||
break;
|
||||
case KindCode::same:
|
||||
CHECK(sameArg);
|
||||
if (std::optional<DynamicType> aType{sameArg->GetType()}) {
|
||||
@ -2158,7 +2166,6 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
|
||||
case KindCode::exactKind:
|
||||
resultType = DynamicType{*category, result.exactKindValue};
|
||||
break;
|
||||
case KindCode::defaultCharKind:
|
||||
case KindCode::typeless:
|
||||
case KindCode::any:
|
||||
case KindCode::kindArg:
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "flang/Frontend/CompilerInvocation.h"
|
||||
#include "flang/Common/Fortran-features.h"
|
||||
#include "flang/Common/Version.h"
|
||||
#include "flang/Frontend/CodeGenOptions.h"
|
||||
#include "flang/Frontend/PreprocessorOptions.h"
|
||||
#include "flang/Frontend/TargetOptions.h"
|
||||
@ -36,6 +37,7 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/TargetParser/Host.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
@ -869,7 +871,7 @@ static bool parseFloatingPointArgs(CompilerInvocation &invoc,
|
||||
|
||||
bool CompilerInvocation::createFromArgs(
|
||||
CompilerInvocation &res, llvm::ArrayRef<const char *> commandLineArgs,
|
||||
clang::DiagnosticsEngine &diags) {
|
||||
clang::DiagnosticsEngine &diags, const char *argv0) {
|
||||
|
||||
bool success = true;
|
||||
|
||||
@ -929,6 +931,23 @@ bool CompilerInvocation::createFromArgs(
|
||||
|
||||
success &= parseFloatingPointArgs(res, args, diags);
|
||||
|
||||
// Set the string to be used as the return value of the COMPILER_OPTIONS
|
||||
// intrinsic of iso_fortran_env. This is either passed in from the parent
|
||||
// compiler driver invocation with an environment variable, or failing that
|
||||
// set to the command line arguments of the frontend driver invocation.
|
||||
res.allCompilerInvocOpts = std::string();
|
||||
llvm::raw_string_ostream os(res.allCompilerInvocOpts);
|
||||
char *compilerOptsEnv = std::getenv("FLANG_COMPILER_OPTIONS_STRING");
|
||||
if (compilerOptsEnv != nullptr) {
|
||||
os << compilerOptsEnv;
|
||||
} else {
|
||||
os << argv0 << ' ';
|
||||
for (auto it = commandLineArgs.begin(), e = commandLineArgs.end(); it != e;
|
||||
++it) {
|
||||
os << ' ' << *it;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -1078,6 +1097,11 @@ void CompilerInvocation::setSemanticsOpts(
|
||||
semanticsContext->targetCharacteristics().DisableType(
|
||||
Fortran::common::TypeCategory::Real, /*kind=*/10);
|
||||
}
|
||||
|
||||
std::string version = Fortran::common::getFlangFullVersion();
|
||||
semanticsContext->targetCharacteristics()
|
||||
.set_compilerOptionsString(allCompilerInvocOpts)
|
||||
.set_compilerVersionString(version);
|
||||
}
|
||||
|
||||
/// Set \p loweringOptions controlling lowering behavior based
|
||||
|
@ -73,4 +73,6 @@ module __Fortran_builtins
|
||||
type(__builtin_team_type) :: team_type
|
||||
end type
|
||||
|
||||
intrinsic :: __builtin_compiler_options, __builtin_compiler_version
|
||||
|
||||
end module
|
||||
|
@ -18,7 +18,9 @@ module iso_fortran_env
|
||||
lock_type => __builtin_lock_type, &
|
||||
team_type => __builtin_team_type, &
|
||||
atomic_int_kind => __builtin_atomic_int_kind, &
|
||||
atomic_logical_kind => __builtin_atomic_logical_kind
|
||||
atomic_logical_kind => __builtin_atomic_logical_kind, &
|
||||
compiler_options => __builtin_compiler_options, &
|
||||
compiler_version => __builtin_compiler_version
|
||||
|
||||
implicit none
|
||||
|
||||
@ -145,14 +147,4 @@ module iso_fortran_env
|
||||
integer, parameter :: stat_unlocked = FORTRAN_RUNTIME_STAT_UNLOCKED
|
||||
integer, parameter :: stat_unlocked_failed_image = FORTRAN_RUNTIME_STAT_UNLOCKED_FAILED_IMAGE
|
||||
|
||||
interface compiler_options
|
||||
character(len=80) function compiler_options_1()
|
||||
end function compiler_options_1
|
||||
end interface compiler_options
|
||||
|
||||
interface compiler_version
|
||||
character(len=80) function compiler_version_1()
|
||||
end function compiler_version_1
|
||||
end interface compiler_version
|
||||
|
||||
end module iso_fortran_env
|
||||
|
13
flang/test/Driver/compiler_options.f90
Normal file
13
flang/test/Driver/compiler_options.f90
Normal file
@ -0,0 +1,13 @@
|
||||
! RUN: %flang -S -emit-llvm -o - %s | FileCheck %s
|
||||
! Test communication of COMPILER_OPTIONS from flang-new to flang-new -fc1.
|
||||
! CHECK: [[OPTSVAR:@_QQcl\.[0-9a-f]+]] = linkonce constant [[[OPTSLEN:[0-9]+]] x i8] c"{{.*}}flang-new{{(\.exe)?}} -S -emit-llvm -o - {{.*}}compiler_options.f90"
|
||||
program main
|
||||
use ISO_FORTRAN_ENV, only: compiler_options
|
||||
implicit none
|
||||
character (len = :), allocatable :: v
|
||||
! CHECK: call void @llvm.memmove.p0.p0.i64(ptr %16, ptr [[OPTSVAR]], i64 [[OPTSLEN]], i1 false)
|
||||
v = compiler_options()
|
||||
print *, v
|
||||
deallocate(v)
|
||||
close(1)
|
||||
end program main
|
12
flang/test/Evaluate/compiler_options_fc1.f90
Normal file
12
flang/test/Evaluate/compiler_options_fc1.f90
Normal file
@ -0,0 +1,12 @@
|
||||
! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
|
||||
|
||||
program main
|
||||
use ISO_FORTRAN_ENV, only: compiler_options
|
||||
implicit none
|
||||
character (len = :), allocatable :: v
|
||||
! CHECK: v="{{.*}}flang{{.*}} -fdebug-unparse {{.*}}"
|
||||
v = compiler_options()
|
||||
print *, v
|
||||
deallocate(v)
|
||||
close(1)
|
||||
end program main
|
12
flang/test/Evaluate/compiler_version.f90
Normal file
12
flang/test/Evaluate/compiler_version.f90
Normal file
@ -0,0 +1,12 @@
|
||||
! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
|
||||
|
||||
program main
|
||||
use ISO_FORTRAN_ENV, only: compiler_version
|
||||
implicit none
|
||||
character (len = :), allocatable :: v
|
||||
! CHECK: v="flang version {{.*}}"
|
||||
v = compiler_version()
|
||||
print *, v
|
||||
deallocate(v)
|
||||
close(1)
|
||||
end program main
|
@ -28,7 +28,9 @@
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/TargetParser/Host.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
using llvm::StringRef;
|
||||
|
||||
@ -135,6 +137,28 @@ int main(int argc, const char **argv) {
|
||||
llvm::SmallVector<std::pair<int, const clang::driver::Command *>, 4>
|
||||
failingCommands;
|
||||
|
||||
// Set the environment variable, FLANG_COMPILER_OPTIONS_STRING, to contain all
|
||||
// the compiler options. This is intended for the frontend driver,
|
||||
// flang-new -fc1, to enable the implementation of the COMPILER_OPTIONS
|
||||
// intrinsic. To this end, the frontend driver requires the list of the
|
||||
// original compiler options, which is not available through other means.
|
||||
// TODO: This way of passing information between the compiler and frontend
|
||||
// drivers is discouraged. We should find a better way not involving env
|
||||
// variables.
|
||||
std::string compilerOptsGathered;
|
||||
llvm::raw_string_ostream os(compilerOptsGathered);
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
os << argv[i];
|
||||
if (i < argc - 1) {
|
||||
os << ' ';
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
_putenv_s("FLANG_COMPILER_OPTIONS_STRING", compilerOptsGathered.c_str());
|
||||
#else
|
||||
setenv("FLANG_COMPILER_OPTIONS_STRING", compilerOptsGathered.c_str(), 1);
|
||||
#endif
|
||||
|
||||
// Run the driver
|
||||
int res = 1;
|
||||
bool isCrash = false;
|
||||
|
@ -50,8 +50,8 @@ int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0) {
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
|
||||
new clang::DiagnosticOptions();
|
||||
clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer);
|
||||
bool success =
|
||||
CompilerInvocation::createFromArgs(flang->getInvocation(), argv, diags);
|
||||
bool success = CompilerInvocation::createFromArgs(flang->getInvocation(),
|
||||
argv, diags, argv0);
|
||||
|
||||
// Initialize targets first, so that --version shows registered targets.
|
||||
llvm::InitializeAllTargets();
|
||||
|
Loading…
Reference in New Issue
Block a user