Skip to content

Commit 541f5c4

Browse files
committed
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
1 parent 2129cc1 commit 541f5c4

File tree

15 files changed

+328
-16
lines changed

15 files changed

+328
-16
lines changed

flang/include/flang/Common/Version.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===- Version.h - Flang Version Number ---------------------*- Fortran -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file
10+
/// Defines version macros and version-related utility functions
11+
/// for Flang.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_FLANG_COMMON_VERSION_H
16+
#define LLVM_FLANG_COMMON_VERSION_H
17+
18+
#include "flang/Version.inc"
19+
#include "llvm/ADT/StringRef.h"
20+
21+
namespace Fortran::common {
22+
/// Retrieves the repository path (e.g., Git path) that
23+
/// identifies the particular Flang branch, tag, or trunk from which this
24+
/// Flang was built.
25+
std::string getFlangRepositoryPath();
26+
27+
/// Retrieves the repository path from which LLVM was built.
28+
///
29+
/// This supports LLVM residing in a separate repository from flang.
30+
std::string getLLVMRepositoryPath();
31+
32+
/// Retrieves the repository revision number (or identifier) from which
33+
/// this Flang was built.
34+
std::string getFlangRevision();
35+
36+
/// Retrieves the repository revision number (or identifier) from which
37+
/// LLVM was built.
38+
///
39+
/// If Flang and LLVM are in the same repository, this returns the same
40+
/// string as getFlangRevision.
41+
std::string getLLVMRevision();
42+
43+
/// Retrieves the full repository version that is an amalgamation of
44+
/// the information in getFlangRepositoryPath() and getFlangRevision().
45+
std::string getFlangFullRepositoryVersion();
46+
47+
/// Retrieves a string representing the complete flang version,
48+
/// which includes the flang version number, the repository version,
49+
/// and the vendor tag.
50+
std::string getFlangFullVersion();
51+
52+
/// Like getFlangFullVersion(), but with a custom tool name.
53+
std::string getFlangToolFullVersion(llvm::StringRef ToolName);
54+
} // namespace Fortran::common
55+
56+
#endif // LLVM_FLANG_COMMON_VERSION_H

flang/include/flang/Evaluate/target.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,22 @@ class TargetCharacteristics {
7575

7676
static Rounding defaultRounding;
7777

78+
const std::string &compilerOptionsString() const {
79+
return compilerOptionsString_;
80+
};
81+
TargetCharacteristics &set_compilerOptionsString(std::string x) {
82+
compilerOptionsString_ = x;
83+
return *this;
84+
}
85+
86+
const std::string &compilerVersionString() const {
87+
return compilerVersionString_;
88+
};
89+
TargetCharacteristics &set_compilerVersionString(std::string x) {
90+
compilerVersionString_ = x;
91+
return *this;
92+
}
93+
7894
private:
7995
static constexpr int maxKind{32};
8096
std::uint8_t byteSize_[common::TypeCategory_enumSize][maxKind]{};
@@ -87,6 +103,8 @@ class TargetCharacteristics {
87103
std::size_t descriptorAlignment_{8};
88104
std::size_t maxByteSize_{8 /*at least*/};
89105
std::size_t maxAlignment_{8 /*at least*/};
106+
std::string compilerOptionsString_;
107+
std::string compilerVersionString_;
90108
};
91109

92110
} // namespace Fortran::evaluate

flang/include/flang/Frontend/CompilerInvocation.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ class CompilerInvocation : public CompilerInvocationBase {
8282
/// Options controlling language dialect.
8383
Fortran::frontend::LangOptions langOpts;
8484

85+
// The original invocation of the compiler driver.
86+
// This string will be set as the return value from the COMPILER_OPTIONS
87+
// intrinsic of iso_fortran_env.
88+
std::string allCompilerInvocOpts;
89+
8590
// Semantics context
8691
std::unique_ptr<Fortran::semantics::SemanticsContext> semanticsContext;
8792

@@ -208,7 +213,8 @@ class CompilerInvocation : public CompilerInvocationBase {
208213
/// \param [out] res - The resulting invocation.
209214
static bool createFromArgs(CompilerInvocation &res,
210215
llvm::ArrayRef<const char *> commandLineArgs,
211-
clang::DiagnosticsEngine &diags);
216+
clang::DiagnosticsEngine &diags,
217+
const char *argv0 = nullptr);
212218

213219
// Enables the std=f2018 conformance check
214220
void setEnableConformanceChecks() { enableConformanceChecks = true; }

flang/lib/Common/CMakeLists.txt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,45 @@
1+
find_first_existing_vc_file("${LLVM_MAIN_SRC_DIR}" llvm_vc)
2+
find_first_existing_vc_file("${FLANG_SOURCE_DIR}" flang_vc)
3+
4+
# The VC revision include that we want to generate.
5+
set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSVersion.inc")
6+
7+
set(generate_vcs_version_script "${LLVM_CMAKE_DIR}/GenerateVersionFromVCS.cmake")
8+
9+
if(llvm_vc AND LLVM_APPEND_VC_REV)
10+
set(llvm_source_dir ${LLVM_MAIN_SRC_DIR})
11+
endif()
12+
if(flang_vc AND LLVM_APPEND_VC_REV)
13+
set(flang_source_dir ${FLANG_SOURCE_DIR})
14+
endif()
15+
16+
# Create custom target to generate the VC revision include.
17+
add_custom_command(OUTPUT "${version_inc}"
18+
DEPENDS "${llvm_vc}" "${flang_vc}" "${generate_vcs_version_script}"
19+
COMMAND ${CMAKE_COMMAND} "-DNAMES=\"LLVM;FLANG\""
20+
"-DLLVM_SOURCE_DIR=${llvm_source_dir}"
21+
"-DFLANG_SOURCE_DIR=${flang_source_dir}"
22+
"-DHEADER_FILE=${version_inc}"
23+
-P "${generate_vcs_version_script}")
24+
25+
# Mark the generated header as being generated.
26+
set_source_files_properties("${version_inc}"
27+
PROPERTIES GENERATED TRUE
28+
HEADER_FILE_ONLY TRUE)
29+
30+
if(FLANG_VENDOR)
31+
set_source_files_properties(Version.cpp
32+
PROPERTIES COMPILE_DEFINITIONS "FLANG_VENDOR=\"${FLANG_VENDOR} \"")
33+
endif()
34+
135

236
add_flang_library(FortranCommon
337
Fortran.cpp
438
Fortran-features.cpp
539
default-kinds.cpp
640
idioms.cpp
41+
Version.cpp
42+
${version_inc}
743

844
LINK_COMPONENTS
945
Support

flang/lib/Common/Version.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//===- Version.cpp - Flang Version Number -------------------*- Fortran -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines several version-related utility functions for Flang.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "flang/Common/Version.h"
14+
#include "llvm/Support/raw_ostream.h"
15+
#include <cstdlib>
16+
#include <cstring>
17+
18+
#include "VCSVersion.inc"
19+
20+
namespace Fortran::common {
21+
22+
std::string getFlangRepositoryPath() {
23+
#if defined(FLANG_REPOSITORY_STRING)
24+
return FLANG_REPOSITORY_STRING;
25+
#else
26+
#ifdef FLANG_REPOSITORY
27+
return FLANG_REPOSITORY;
28+
#else
29+
return "";
30+
#endif
31+
#endif
32+
}
33+
34+
std::string getLLVMRepositoryPath() {
35+
#ifdef LLVM_REPOSITORY
36+
return LLVM_REPOSITORY;
37+
#else
38+
return "";
39+
#endif
40+
}
41+
42+
std::string getFlangRevision() {
43+
#ifdef FLANG_REVISION
44+
return FLANG_REVISION;
45+
#else
46+
return "";
47+
#endif
48+
}
49+
50+
std::string getLLVMRevision() {
51+
#ifdef LLVM_REVISION
52+
return LLVM_REVISION;
53+
#else
54+
return "";
55+
#endif
56+
}
57+
58+
std::string getFlangFullRepositoryVersion() {
59+
std::string buf;
60+
llvm::raw_string_ostream OS(buf);
61+
std::string Path = getFlangRepositoryPath();
62+
std::string Revision = getFlangRevision();
63+
if (!Path.empty() || !Revision.empty()) {
64+
OS << '(';
65+
if (!Path.empty())
66+
OS << Path;
67+
if (!Revision.empty()) {
68+
if (!Path.empty())
69+
OS << ' ';
70+
OS << Revision;
71+
}
72+
OS << ')';
73+
}
74+
// Support LLVM in a separate repository.
75+
std::string LLVMRev = getLLVMRevision();
76+
if (!LLVMRev.empty() && LLVMRev != Revision) {
77+
OS << " (";
78+
std::string LLVMRepo = getLLVMRepositoryPath();
79+
if (!LLVMRepo.empty())
80+
OS << LLVMRepo << ' ';
81+
OS << LLVMRev << ')';
82+
}
83+
return buf;
84+
}
85+
86+
std::string getFlangFullVersion() { return getFlangToolFullVersion("flang"); }
87+
88+
std::string getFlangToolFullVersion(llvm::StringRef ToolName) {
89+
std::string buf;
90+
llvm::raw_string_ostream OS(buf);
91+
#ifdef FLANG_VENDOR
92+
OS << FLANG_VENDOR;
93+
#endif
94+
OS << ToolName << " version " FLANG_VERSION_STRING;
95+
96+
std::string repo = getFlangFullRepositoryVersion();
97+
if (!repo.empty()) {
98+
OS << " " << repo;
99+
}
100+
101+
return buf;
102+
}
103+
104+
} // end namespace Fortran::common

flang/lib/Evaluate/fold-character.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
118118
return Expr<T>{Constant<T>{
119119
CharacterUtils<KIND>::TRIM(std::get<Scalar<T>>(*scalar))}};
120120
}
121+
} else if (name == "__builtin_compiler_options") {
122+
auto &o = context.targetCharacteristics().compilerOptionsString();
123+
return Expr<T>{Constant<T>{StringType(o.begin(), o.end())}};
124+
} else if (name == "__builtin_compiler_version") {
125+
auto &v = context.targetCharacteristics().compilerVersionString();
126+
return Expr<T>{Constant<T>{StringType(v.begin(), v.end())}};
121127
}
122128
return Expr<T>{std::move(funcRef)};
123129
}

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,8 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
916916
{"__builtin_ieee_support_underflow_control",
917917
{{"x", AnyReal, Rank::elemental, Optionality::optional}},
918918
DefaultLogical},
919+
{"__builtin_compiler_options", {}, DefaultChar},
920+
{"__builtin_compiler_version", {}, DefaultChar},
919921
};
920922

921923
// TODO: Coarray intrinsic functions
@@ -2070,6 +2072,12 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
20702072
resultType = DynamicType{TypeCategory::Logical,
20712073
defaults.GetDefaultKind(TypeCategory::Logical)};
20722074
break;
2075+
case KindCode::defaultCharKind:
2076+
CHECK(result.categorySet == CharType);
2077+
CHECK(*category == TypeCategory::Character);
2078+
resultType = DynamicType{TypeCategory::Character,
2079+
defaults.GetDefaultKind(TypeCategory::Character)};
2080+
break;
20732081
case KindCode::same:
20742082
CHECK(sameArg);
20752083
if (std::optional<DynamicType> aType{sameArg->GetType()}) {
@@ -2158,7 +2166,6 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
21582166
case KindCode::exactKind:
21592167
resultType = DynamicType{*category, result.exactKindValue};
21602168
break;
2161-
case KindCode::defaultCharKind:
21622169
case KindCode::typeless:
21632170
case KindCode::any:
21642171
case KindCode::kindArg:

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "flang/Frontend/CompilerInvocation.h"
1414
#include "flang/Common/Fortran-features.h"
15+
#include "flang/Common/Version.h"
1516
#include "flang/Frontend/CodeGenOptions.h"
1617
#include "flang/Frontend/PreprocessorOptions.h"
1718
#include "flang/Frontend/TargetOptions.h"
@@ -36,6 +37,7 @@
3637
#include "llvm/Support/raw_ostream.h"
3738
#include "llvm/TargetParser/Host.h"
3839
#include "llvm/TargetParser/Triple.h"
40+
#include <cstdlib>
3941
#include <memory>
4042
#include <optional>
4143

@@ -869,7 +871,7 @@ static bool parseFloatingPointArgs(CompilerInvocation &invoc,
869871

870872
bool CompilerInvocation::createFromArgs(
871873
CompilerInvocation &res, llvm::ArrayRef<const char *> commandLineArgs,
872-
clang::DiagnosticsEngine &diags) {
874+
clang::DiagnosticsEngine &diags, const char *argv0) {
873875

874876
bool success = true;
875877

@@ -929,6 +931,23 @@ bool CompilerInvocation::createFromArgs(
929931

930932
success &= parseFloatingPointArgs(res, args, diags);
931933

934+
// Set the string to be used as the return value of the COMPILER_OPTIONS
935+
// intrinsic of iso_fortran_env. This is either passed in from the parent
936+
// compiler driver invocation with an environment variable, or failing that
937+
// set to the command line arguments of the frontend driver invocation.
938+
res.allCompilerInvocOpts = std::string();
939+
llvm::raw_string_ostream os(res.allCompilerInvocOpts);
940+
char *compilerOptsEnv = std::getenv("FLANG_COMPILER_OPTIONS_STRING");
941+
if (compilerOptsEnv != nullptr) {
942+
os << compilerOptsEnv;
943+
} else {
944+
os << argv0 << ' ';
945+
for (auto it = commandLineArgs.begin(), e = commandLineArgs.end(); it != e;
946+
++it) {
947+
os << ' ' << *it;
948+
}
949+
}
950+
932951
return success;
933952
}
934953

@@ -1078,6 +1097,11 @@ void CompilerInvocation::setSemanticsOpts(
10781097
semanticsContext->targetCharacteristics().DisableType(
10791098
Fortran::common::TypeCategory::Real, /*kind=*/10);
10801099
}
1100+
1101+
std::string version = Fortran::common::getFlangFullVersion();
1102+
semanticsContext->targetCharacteristics()
1103+
.set_compilerOptionsString(allCompilerInvocOpts)
1104+
.set_compilerVersionString(version);
10811105
}
10821106

10831107
/// Set \p loweringOptions controlling lowering behavior based

flang/module/__fortran_builtins.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,6 @@
7373
type(__builtin_team_type) :: team_type
7474
end type
7575

76+
intrinsic :: __builtin_compiler_options, __builtin_compiler_version
77+
7678
end module

flang/module/iso_fortran_env.f90

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ module iso_fortran_env
1818
lock_type => __builtin_lock_type, &
1919
team_type => __builtin_team_type, &
2020
atomic_int_kind => __builtin_atomic_int_kind, &
21-
atomic_logical_kind => __builtin_atomic_logical_kind
21+
atomic_logical_kind => __builtin_atomic_logical_kind, &
22+
compiler_options => __builtin_compiler_options, &
23+
compiler_version => __builtin_compiler_version
2224

2325
implicit none
2426

@@ -145,14 +147,4 @@ module iso_fortran_env
145147
integer, parameter :: stat_unlocked = FORTRAN_RUNTIME_STAT_UNLOCKED
146148
integer, parameter :: stat_unlocked_failed_image = FORTRAN_RUNTIME_STAT_UNLOCKED_FAILED_IMAGE
147149

148-
interface compiler_options
149-
character(len=80) function compiler_options_1()
150-
end function compiler_options_1
151-
end interface compiler_options
152-
153-
interface compiler_version
154-
character(len=80) function compiler_version_1()
155-
end function compiler_version_1
156-
end interface compiler_version
157-
158150
end module iso_fortran_env

0 commit comments

Comments
 (0)