forked from OSchip/llvm-project
[flang][driver] Add `-fno-analyzed-objects-for-unparse`
This patch adds a new option for the new Flang driver: `-fno-analyzed-objects-for-unparse`. The semantics are similar to `-funparse-typed-exprs-to-f18-fc` from `f18`. For consistency, the latter is replaced with `-fno-analyzed-objects-for-unparse`. The new option controls the behaviour of the unparser (i.e. the action corresponding to `-fdebug-unparse`). The default behaviour is to use the analyzed objects when unparsing. The new flag can be used to turn this off, so that the original parse-tree objects are used. The analyzed objects are generated during the semantic checks [1]. This patch also updates the semantics of `-fno-analyzed-objects-for-unparse`/`-funparse-typed-exprs-to-f18-fc` in `f18`, so that this flag is always taken into account when `Unparse` is used (this way the semantics in `f18` and `flang-new` are identical). The added test file is based on example from Peter Steinfeld. [1] https://github.com/llvm/llvm-project/blob/main/flang/docs/Semantics.md Differential Revision: https://reviews.llvm.org/D103612
This commit is contained in:
parent
f7b1fa6f5e
commit
2a7bb8494e
|
@ -4536,6 +4536,11 @@ def fget_symbols_sources : Flag<["-"], "fget-symbols-sources">, Group<Action_Gro
|
|||
|
||||
def module_suffix : Separate<["-"], "module-suffix">, Group<f_Group>, MetaVarName<"<suffix>">,
|
||||
HelpText<"Use <suffix> as the suffix for module files (the default value is `.mod`)">;
|
||||
def fanalyzed_objects_for_unparse : Flag<["-"],
|
||||
"fanalyzed-objects-for-unparse">, Group<f_Group>;
|
||||
def fno_analyzed_objects_for_unparse : Flag<["-"],
|
||||
"fno-analyzed-objects-for-unparse">, Group<f_Group>,
|
||||
HelpText<"Do not use the analyzed objects when unparsing">;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -75,11 +75,39 @@ class CompilerInvocation : public CompilerInvocationBase {
|
|||
|
||||
bool warnAsErr_ = false;
|
||||
|
||||
/// This flag controls the unparsing and is used to decide whether to print out
|
||||
/// the semantically analyzed version of an object or expression or the plain
|
||||
/// version that does not include any information from semantic analysis.
|
||||
bool useAnalyzedObjectsForUnparse_ = true;
|
||||
|
||||
// Fortran Dialect options
|
||||
Fortran::common::IntrinsicTypeDefaultKinds defaultKinds_;
|
||||
|
||||
bool EnableConformanceChecks_ = false;
|
||||
|
||||
/// Used in e.g. unparsing to dump the analyzed rather than the original
|
||||
/// parse-tree objects.
|
||||
Fortran::parser::AnalyzedObjectsAsFortran AsFortran_{
|
||||
[](llvm::raw_ostream &o, const Fortran::evaluate::GenericExprWrapper &x) {
|
||||
if (x.v) {
|
||||
x.v->AsFortran(o);
|
||||
} else {
|
||||
o << "(bad expression)";
|
||||
}
|
||||
},
|
||||
[](llvm::raw_ostream &o,
|
||||
const Fortran::evaluate::GenericAssignmentWrapper &x) {
|
||||
if (x.v) {
|
||||
x.v->AsFortran(o);
|
||||
} else {
|
||||
o << "(bad assignment)";
|
||||
}
|
||||
},
|
||||
[](llvm::raw_ostream &o, const Fortran::evaluate::ProcedureRef &x) {
|
||||
x.AsFortran(o << "CALL ");
|
||||
},
|
||||
};
|
||||
|
||||
public:
|
||||
CompilerInvocation() = default;
|
||||
|
||||
|
@ -108,11 +136,21 @@ public:
|
|||
bool &warnAsErr() { return warnAsErr_; }
|
||||
const bool &warnAsErr() const { return warnAsErr_; }
|
||||
|
||||
bool &useAnalyzedObjectsForUnparse() { return useAnalyzedObjectsForUnparse_; }
|
||||
const bool &useAnalyzedObjectsForUnparse() const {
|
||||
return useAnalyzedObjectsForUnparse_;
|
||||
}
|
||||
|
||||
bool &enableConformanceChecks() { return EnableConformanceChecks_; }
|
||||
const bool &enableConformanceChecks() const {
|
||||
return EnableConformanceChecks_;
|
||||
}
|
||||
|
||||
Fortran::parser::AnalyzedObjectsAsFortran &asFortran() { return AsFortran_; }
|
||||
const Fortran::parser::AnalyzedObjectsAsFortran &asFortran() const {
|
||||
return AsFortran_;
|
||||
}
|
||||
|
||||
Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds() {
|
||||
return defaultKinds_;
|
||||
}
|
||||
|
@ -142,6 +180,10 @@ public:
|
|||
|
||||
void SetWarnAsErr(bool flag) { warnAsErr_ = flag; }
|
||||
|
||||
void SetUseAnalyzedObjectsForUnparse(bool flag) {
|
||||
useAnalyzedObjectsForUnparse_ = flag;
|
||||
}
|
||||
|
||||
/// Set the Fortran options to predifined defaults. These defaults are
|
||||
/// consistend with f18/f18.cpp.
|
||||
// TODO: We should map frontendOpts_ to parserOpts_ instead. For that, we
|
||||
|
|
|
@ -404,6 +404,12 @@ static bool parseSemaArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
|
|||
res.SetModuleFileSuffix(moduleSuffix->getValue());
|
||||
}
|
||||
|
||||
// -fno-analyzed-objects-for-unparse
|
||||
if (args.hasArg(
|
||||
clang::driver::options::OPT_fno_analyzed_objects_for_unparse)) {
|
||||
res.SetUseAnalyzedObjectsForUnparse(false);
|
||||
}
|
||||
|
||||
return diags.getNumErrors() == numErrorsBefore;
|
||||
}
|
||||
|
||||
|
|
|
@ -242,28 +242,27 @@ void ParseSyntaxOnlyAction::ExecuteAction() {
|
|||
}
|
||||
|
||||
void DebugUnparseNoSemaAction::ExecuteAction() {
|
||||
auto &invoc = this->instance().invocation();
|
||||
auto &parseTree{instance().parsing().parseTree()};
|
||||
|
||||
Fortran::parser::AnalyzedObjectsAsFortran asFortran =
|
||||
Fortran::frontend::getBasicAsFortran();
|
||||
|
||||
// TODO: Options should come from CompilerInvocation
|
||||
Unparse(llvm::outs(), *parseTree,
|
||||
/*encoding=*/Fortran::parser::Encoding::UTF_8,
|
||||
/*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
|
||||
/*preStatement=*/nullptr, &asFortran);
|
||||
/*preStatement=*/nullptr,
|
||||
invoc.useAnalyzedObjectsForUnparse() ? &invoc.asFortran() : nullptr);
|
||||
}
|
||||
|
||||
void DebugUnparseAction::ExecuteAction() {
|
||||
auto &invoc = this->instance().invocation();
|
||||
auto &parseTree{instance().parsing().parseTree()};
|
||||
Fortran::parser::AnalyzedObjectsAsFortran asFortran =
|
||||
Fortran::frontend::getBasicAsFortran();
|
||||
|
||||
// TODO: Options should come from CompilerInvocation
|
||||
Unparse(llvm::outs(), *parseTree,
|
||||
/*encoding=*/Fortran::parser::Encoding::UTF_8,
|
||||
/*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
|
||||
/*preStatement=*/nullptr, &asFortran);
|
||||
/*preStatement=*/nullptr,
|
||||
invoc.useAnalyzedObjectsForUnparse() ? &invoc.asFortran() : nullptr);
|
||||
|
||||
// Report fatal semantic errors
|
||||
reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
|
||||
|
@ -310,12 +309,11 @@ void DebugDumpAllAction::ExecuteAction() {
|
|||
|
||||
// Dump parse tree
|
||||
auto &parseTree{instance().parsing().parseTree()};
|
||||
Fortran::parser::AnalyzedObjectsAsFortran asFortran =
|
||||
Fortran::frontend::getBasicAsFortran();
|
||||
llvm::outs() << "========================";
|
||||
llvm::outs() << " Flang: parse tree dump ";
|
||||
llvm::outs() << "========================\n";
|
||||
Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran);
|
||||
Fortran::parser::DumpTree(
|
||||
llvm::outs(), parseTree, &ci.invocation().asFortran());
|
||||
|
||||
auto &semantics = this->semantics();
|
||||
auto tables{Fortran::semantics::BuildRuntimeDerivedTypeTables(
|
||||
|
@ -343,20 +341,19 @@ void DebugDumpAllAction::ExecuteAction() {
|
|||
|
||||
void DebugDumpParseTreeNoSemaAction::ExecuteAction() {
|
||||
auto &parseTree{instance().parsing().parseTree()};
|
||||
Fortran::parser::AnalyzedObjectsAsFortran asFortran =
|
||||
Fortran::frontend::getBasicAsFortran();
|
||||
|
||||
// Dump parse tree
|
||||
Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran);
|
||||
Fortran::parser::DumpTree(
|
||||
llvm::outs(), parseTree, &this->instance().invocation().asFortran());
|
||||
}
|
||||
|
||||
void DebugDumpParseTreeAction::ExecuteAction() {
|
||||
auto &parseTree{instance().parsing().parseTree()};
|
||||
Fortran::parser::AnalyzedObjectsAsFortran asFortran =
|
||||
Fortran::frontend::getBasicAsFortran();
|
||||
|
||||
// Dump parse tree
|
||||
Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran);
|
||||
Fortran::parser::DumpTree(
|
||||
llvm::outs(), parseTree, &this->instance().invocation().asFortran());
|
||||
|
||||
// Report fatal semantic errors
|
||||
reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
|
||||
GetCurrentFileOrBufferName());
|
||||
|
|
|
@ -32,34 +32,6 @@ bool Fortran::frontend::mustBePreprocessed(llvm::StringRef suffix) {
|
|||
suffix == "F03" || suffix == "F08" || suffix == "F18";
|
||||
}
|
||||
|
||||
// TODO: This is a copy of `asFortran` from f18.cpp and is added here for
|
||||
// compatiblity. It doesn't really belong here, but I couldn't find a better
|
||||
// place. We should decide whether to add it to the Evaluate or Parse/Unparse
|
||||
// APIs or some dedicated utility library in the driver.
|
||||
Fortran::parser::AnalyzedObjectsAsFortran
|
||||
Fortran::frontend::getBasicAsFortran() {
|
||||
return Fortran::parser::AnalyzedObjectsAsFortran{
|
||||
[](llvm::raw_ostream &o, const Fortran::evaluate::GenericExprWrapper &x) {
|
||||
if (x.v) {
|
||||
x.v->AsFortran(o);
|
||||
} else {
|
||||
o << "(bad expression)";
|
||||
}
|
||||
},
|
||||
[](llvm::raw_ostream &o,
|
||||
const Fortran::evaluate::GenericAssignmentWrapper &x) {
|
||||
if (x.v) {
|
||||
x.v->AsFortran(o);
|
||||
} else {
|
||||
o << "(bad assignment)";
|
||||
}
|
||||
},
|
||||
[](llvm::raw_ostream &o, const Fortran::evaluate::ProcedureRef &x) {
|
||||
x.AsFortran(o << "CALL ");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
InputKind FrontendOptions::GetInputKindForExtension(llvm::StringRef extension) {
|
||||
if (isFixedFormSuffix(extension) || isFreeFormSuffix(extension)) {
|
||||
return Language::Fortran;
|
||||
|
|
|
@ -101,6 +101,8 @@
|
|||
! HELP-FC1-NEXT: Specify where to find the compiled intrinsic modules
|
||||
! HELP-FC1-NEXT: -flarge-sizes Use INTEGER(KIND=8) for the result type in size-related intrinsics
|
||||
! HELP-FC1-NEXT: -flogical-abbreviations Enable logical abbreviations
|
||||
! HELP-FC1-NEXT: -fno-analyzed-objects-for-unparse
|
||||
! HELP-FC1-NEXT: Do not use the analyzed objects when unparsing
|
||||
! HELP-FC1-NEXT: -fopenacc Enable OpenACC
|
||||
! HELP-FC1-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code.
|
||||
! HELP-FC1-NEXT: -fxor-operator Enable .XOR. as a synonym of .NEQV.
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
! Tests `-fno-analyzed-exprs-as-fortran` frontend option
|
||||
|
||||
!--------------------------
|
||||
! RUN lines
|
||||
!--------------------------
|
||||
! RUN: %flang_fc1 -fdebug-unparse %s | FileCheck %s --check-prefix=DEFAULT
|
||||
! RUN: %flang_fc1 -fdebug-unparse -fno-analyzed-objects-for-unparse %s | FileCheck %s --check-prefix=DISABLED
|
||||
|
||||
!------------------------------------------------
|
||||
! EXPECTED OUTPUT: default - use analyzed objects
|
||||
!------------------------------------------------
|
||||
! DEFAULT: PROGRAM test
|
||||
! DEFAULT-NEXT: REAL, PARAMETER :: val = 3.43e2_4
|
||||
! DEFAULT-NEXT: PRINT *, 3.47e2_4
|
||||
! DEFAULT-NEXT: END PROGRAM
|
||||
|
||||
!-----------------------------------------------------------
|
||||
! EXPECTED OUTPUT: disabled - don't use the analyzed objects
|
||||
!-----------------------------------------------------------
|
||||
! DISABLED: PROGRAM test
|
||||
! DISABLED-NEXT: REAL, PARAMETER :: val = 343.0
|
||||
! DISABLED-NEXT: PRINT *, val+4
|
||||
! DISABLED-NEXT: END PROGRAM
|
||||
|
||||
!--------------------------
|
||||
! INPUT
|
||||
!--------------------------
|
||||
program test
|
||||
real, parameter :: val = 343.0
|
||||
print *, val + 4
|
||||
end program
|
|
@ -105,7 +105,7 @@ struct DriverOptions {
|
|||
bool debugModuleWriter{false};
|
||||
bool defaultReal8{false};
|
||||
bool measureTree{false};
|
||||
bool unparseTypedExprsToF18_FC{false};
|
||||
bool useAnalyzedObjectsForUnparse{true};
|
||||
std::vector<std::string> F18_FCArgs;
|
||||
const char *prefix{nullptr};
|
||||
bool getDefinition{false};
|
||||
|
@ -322,7 +322,8 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options,
|
|||
Unparse(llvm::outs(), parseTree, driver.encoding, true /*capitalize*/,
|
||||
options.features.IsEnabled(
|
||||
Fortran::common::LanguageFeature::BackslashEscapes),
|
||||
nullptr /* action before each statement */, &asFortran);
|
||||
nullptr /* action before each statement */,
|
||||
driver.useAnalyzedObjectsForUnparse ? &asFortran : nullptr);
|
||||
return {};
|
||||
}
|
||||
if (driver.dumpPreFirTree) {
|
||||
|
@ -353,7 +354,7 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options,
|
|||
options.features.IsEnabled(
|
||||
Fortran::common::LanguageFeature::BackslashEscapes),
|
||||
nullptr /* action before each statement */,
|
||||
driver.unparseTypedExprsToF18_FC ? &asFortran : nullptr);
|
||||
driver.useAnalyzedObjectsForUnparse ? &asFortran : nullptr);
|
||||
}
|
||||
|
||||
RunOtherCompiler(driver, tmpSourcePath.data(), relo.data());
|
||||
|
@ -578,8 +579,8 @@ int main(int argc, char *const argv[]) {
|
|||
} else if (arg == "-funparse-with-symbols" ||
|
||||
arg == "-fdebug-unparse-with-symbols") {
|
||||
driver.dumpUnparseWithSymbols = true;
|
||||
} else if (arg == "-funparse-typed-exprs-to-f18-fc") {
|
||||
driver.unparseTypedExprsToF18_FC = true;
|
||||
} else if (arg == "-fno-analyzed-objects-for-unparse") {
|
||||
driver.useAnalyzedObjectsForUnparse = false;
|
||||
} else if (arg == "-fparse-only" || arg == "-fsyntax-only") {
|
||||
driver.syntaxOnly = true;
|
||||
} else if (arg == "-c") {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#===------------------------------------------------------------------------===#
|
||||
|
||||
wd=$(cd $(dirname "$0")/.. && pwd)
|
||||
opts="-module-suffix .f18.mod "
|
||||
opts="-fno-analyzed-objects-for-unparse -module-suffix .f18.mod "
|
||||
if ! $wd/bin/f18 $opts "$@"
|
||||
then status=$?
|
||||
echo flang: in $PWD, f18 failed with exit status $status: $wd/bin/f18 $opts "$@" >&2
|
||||
|
|
Loading…
Reference in New Issue