aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Frontend/CompilerInvocation.cpp
diff options
context:
space:
mode:
authorJan Svoboda <jan_svoboda@apple.com>2021-02-09 10:17:04 +0100
committerJan Svoboda <jan_svoboda@apple.com>2021-02-09 10:18:55 +0100
commit40c261c41c4ceb0dff802d6a83f7ae65af936af8 (patch)
tree924ac203f9a330eafb51ac73c2806e171aaefe9c /clang/lib/Frontend/CompilerInvocation.cpp
parentd82679d8050130522ebcf90c6061211a25b1c83d (diff)
downloadllvm-40c261c41c4ceb0dff802d6a83f7ae65af936af8.zip
llvm-40c261c41c4ceb0dff802d6a83f7ae65af936af8.tar.gz
llvm-40c261c41c4ceb0dff802d6a83f7ae65af936af8.tar.bz2
[clang][cli] Generate and round-trip language options
This patch implements generation of remaining language options and tests it by performing parse-generate-parse round trip (on by default for assert builds, off otherwise). This patch also correctly reports failures in `parseSanitizerKinds`, which is necessary for emitting diagnostics when an invalid sanitizer is passed to `-fsanitize=` during round-trip. This patch also removes TableGen marshalling classes from two options: * `fsanitize_blacklist` When parsing: it's first initialized via the generated code, but then also changed by manually written code, which is confusing. * `fopenmp` When parsing: it's first initialized via generated code, but then conditionally changed by manually written code. This is also confusing. Moreover, we need to do some extra checks when generating it, which would be really cumbersome in TableGen. (Specifically, not emitting it when `-fopenmp-simd` was present.) Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D95793
Diffstat (limited to 'clang/lib/Frontend/CompilerInvocation.cpp')
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp293
1 files changed, 282 insertions, 11 deletions
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 189e7c6..09444b2 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -214,6 +214,7 @@ static void denormalizeStringImpl(SmallVectorImpl<const char *> &Args,
Args.push_back(SA(Value));
break;
case Option::JoinedClass:
+ case Option::CommaJoinedClass:
Args.push_back(SA(Twine(Spelling) + Value));
break;
default:
@@ -1212,6 +1213,12 @@ static void parseSanitizerKinds(StringRef FlagName,
}
}
+static SmallVector<StringRef, 4> serializeSanitizerKinds(SanitizerSet S) {
+ SmallVector<StringRef, 4> Values;
+ serializeSanitizerSet(S, Values);
+ return Values;
+}
+
static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle,
ArgList &Args, DiagnosticsEngine &D,
XRayInstrSet &S) {
@@ -2633,19 +2640,231 @@ static const StringRef GetInputKindName(InputKind IK) {
llvm_unreachable("unknown input language");
}
-static void GenerateLangArgs(const LangOptions &Opts,
- SmallVectorImpl<const char *> &Args,
- CompilerInvocation::StringAllocator SA) {
+void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
+ SmallVectorImpl<const char *> &Args,
+ StringAllocator SA,
+ const llvm::Triple &T) {
+ OptSpecifier StdOpt;
+ switch (Opts.LangStd) {
+ case LangStandard::lang_opencl10:
+ case LangStandard::lang_opencl11:
+ case LangStandard::lang_opencl12:
+ case LangStandard::lang_opencl20:
+ case LangStandard::lang_opencl30:
+ case LangStandard::lang_openclcpp:
+ StdOpt = OPT_cl_std_EQ;
+ break;
+ default:
+ StdOpt = OPT_std_EQ;
+ break;
+ }
+
+ auto LangStandard = LangStandard::getLangStandardForKind(Opts.LangStd);
+ GenerateArg(Args, StdOpt, LangStandard.getName(), SA);
+
if (Opts.IncludeDefaultHeader)
GenerateArg(Args, OPT_finclude_default_header, SA);
if (Opts.DeclareOpenCLBuiltins)
GenerateArg(Args, OPT_fdeclare_opencl_builtins, SA);
+
+ const LangOptions *LangOpts = &Opts;
+
+#define LANG_OPTION_WITH_MARSHALLING( \
+ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
+ DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
+ MERGER, EXTRACTOR, TABLE_INDEX) \
+ GENERATE_OPTION_WITH_MARSHALLING( \
+ Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
+ IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
+#include "clang/Driver/Options.inc"
+#undef LANG_OPTION_WITH_MARSHALLING
+
+ // The '-fcf-protection=' option is generated by CodeGenOpts generator.
+
+ if (Opts.ObjC) {
+ std::string Buffer;
+ llvm::raw_string_ostream Stream(Buffer);
+ Stream << Opts.ObjCRuntime;
+ GenerateArg(Args, OPT_fobjc_runtime_EQ, Stream.str(), SA);
+
+ if (Opts.GC == LangOptions::GCOnly)
+ GenerateArg(Args, OPT_fobjc_gc_only, SA);
+ else if (Opts.GC == LangOptions::HybridGC)
+ GenerateArg(Args, OPT_fobjc_gc, SA);
+ else if (Opts.ObjCAutoRefCount == 1)
+ GenerateArg(Args, OPT_fobjc_arc, SA);
+
+ if (Opts.ObjCWeakRuntime)
+ GenerateArg(Args, OPT_fobjc_runtime_has_weak, SA);
+
+ if (Opts.ObjCWeak)
+ GenerateArg(Args, OPT_fobjc_weak, SA);
+
+ if (Opts.ObjCSubscriptingLegacyRuntime)
+ GenerateArg(Args, OPT_fobjc_subscripting_legacy_runtime, SA);
+ }
+
+ if (Opts.GNUCVersion != 0) {
+ unsigned Major = Opts.GNUCVersion / 100 / 100;
+ unsigned Minor = (Opts.GNUCVersion / 100) % 100;
+ unsigned Patch = Opts.GNUCVersion % 100;
+ GenerateArg(Args, OPT_fgnuc_version_EQ,
+ Twine(Major) + "." + Twine(Minor) + "." + Twine(Patch), SA);
+ }
+
+ if (Opts.SignedOverflowBehavior == LangOptions::SOB_Trapping) {
+ GenerateArg(Args, OPT_ftrapv, SA);
+ GenerateArg(Args, OPT_ftrapv_handler, Opts.OverflowHandler, SA);
+ } else if (Opts.SignedOverflowBehavior == LangOptions::SOB_Defined) {
+ GenerateArg(Args, OPT_fwrapv, SA);
+ }
+
+ if (Opts.MSCompatibilityVersion != 0) {
+ unsigned Major = Opts.MSCompatibilityVersion / 10000000;
+ unsigned Minor = (Opts.MSCompatibilityVersion / 100000) % 100;
+ unsigned Subminor = Opts.MSCompatibilityVersion % 100000;
+ GenerateArg(Args, OPT_fms_compatibility_version,
+ Twine(Major) + "." + Twine(Minor) + "." + Twine(Subminor), SA);
+ }
+
+ if ((!Opts.GNUMode && !Opts.MSVCCompat && !Opts.CPlusPlus17) || T.isOSzOS()) {
+ if (!Opts.Trigraphs)
+ GenerateArg(Args, OPT_fno_trigraphs, SA);
+ } else {
+ if (Opts.Trigraphs)
+ GenerateArg(Args, OPT_ftrigraphs, SA);
+ }
+
+ if (Opts.Blocks && !(Opts.OpenCL && Opts.OpenCLVersion == 200))
+ GenerateArg(Args, OPT_fblocks, SA);
+
+ if (Opts.ConvergentFunctions &&
+ !(Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || Opts.SYCLIsDevice))
+ GenerateArg(Args, OPT_fconvergent_functions, SA);
+
+ if (Opts.NoBuiltin && !Opts.Freestanding)
+ GenerateArg(Args, OPT_fno_builtin, SA);
+
+ // Not generating '-fno-builtin-xxx'. It's handled for CodeGenOptions, that
+ // also read OPT_fno_builtin_.
+
+ if (Opts.LongDoubleSize == 128)
+ GenerateArg(Args, OPT_mlong_double_128, SA);
+ else if (Opts.LongDoubleSize == 64)
+ GenerateArg(Args, OPT_mlong_double_64, SA);
+
+ // Not generating '-mrtd', it's just an alias for '-fdefault-calling-conv='.
+
+ // OpenMP was requested via '-fopenmp', not implied by '-fopenmp-simd' or
+ // '-fopenmp-targets='.
+ if (Opts.OpenMP && !Opts.OpenMPSimd) {
+ GenerateArg(Args, OPT_fopenmp, SA);
+
+ if (Opts.OpenMP != 50)
+ GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA);
+
+ if (!Opts.OpenMPUseTLS)
+ GenerateArg(Args, OPT_fnoopenmp_use_tls, SA);
+
+ if (Opts.OpenMPIsDevice)
+ GenerateArg(Args, OPT_fopenmp_is_device, SA);
+
+ if (Opts.OpenMPIRBuilder)
+ GenerateArg(Args, OPT_fopenmp_enable_irbuilder, SA);
+ }
+
+ if (Opts.OpenMPSimd) {
+ GenerateArg(Args, OPT_fopenmp_simd, SA);
+
+ if (Opts.OpenMP != 50)
+ GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA);
+ }
+
+ if (Opts.OpenMPCUDANumSMs != 0)
+ GenerateArg(Args, OPT_fopenmp_cuda_number_of_sm_EQ,
+ Twine(Opts.OpenMPCUDANumSMs), SA);
+
+ if (Opts.OpenMPCUDABlocksPerSM != 0)
+ GenerateArg(Args, OPT_fopenmp_cuda_blocks_per_sm_EQ,
+ Twine(Opts.OpenMPCUDABlocksPerSM), SA);
+
+ if (Opts.OpenMPCUDAReductionBufNum != 1024)
+ GenerateArg(Args, OPT_fopenmp_cuda_teams_reduction_recs_num_EQ,
+ Twine(Opts.OpenMPCUDAReductionBufNum), SA);
+
+ if (!Opts.OMPTargetTriples.empty()) {
+ std::string Targets;
+ llvm::raw_string_ostream OS(Targets);
+ llvm::interleave(
+ Opts.OMPTargetTriples, OS,
+ [&OS](const llvm::Triple &T) { OS << T.str(); }, ",");
+ GenerateArg(Args, OPT_fopenmp_targets_EQ, OS.str(), SA);
+ }
+
+ if (!Opts.OMPHostIRFile.empty())
+ GenerateArg(Args, OPT_fopenmp_host_ir_file_path, Opts.OMPHostIRFile, SA);
+
+ if (Opts.OpenMPCUDAMode)
+ GenerateArg(Args, OPT_fopenmp_cuda_mode, SA);
+
+ if (Opts.OpenMPCUDATargetParallel)
+ GenerateArg(Args, OPT_fopenmp_cuda_parallel_target_regions, SA);
+
+ if (Opts.OpenMPCUDAForceFullRuntime)
+ GenerateArg(Args, OPT_fopenmp_cuda_force_full_runtime, SA);
+
+ // The arguments used to set 'Optimize' and 'OptimizeSize' will be generated
+ // by CodeGenOptions.
+
+ if (Opts.NoInlineDefine && Opts.Optimize)
+ GenerateArg(Args, OPT_fno_inline, SA);
+
+ if (Opts.DefaultFPContractMode == LangOptions::FPM_Fast)
+ GenerateArg(Args, OPT_ffp_contract, "fast", SA);
+ else if (Opts.DefaultFPContractMode == LangOptions::FPM_On)
+ GenerateArg(Args, OPT_ffp_contract, "on", SA);
+ else if (Opts.DefaultFPContractMode == LangOptions::FPM_Off)
+ GenerateArg(Args, OPT_ffp_contract, "off", SA);
+ else if (Opts.DefaultFPContractMode == LangOptions::FPM_FastHonorPragmas)
+ GenerateArg(Args, OPT_ffp_contract, "fast-honor-pragmas", SA);
+
+ for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
+ GenerateArg(Args, OPT_fsanitize_EQ, Sanitizer, SA);
+
+ // Conflating '-fsanitize-system-blacklist' and '-fsanitize-blacklist'.
+ for (const std::string &F : Opts.SanitizerBlacklistFiles)
+ GenerateArg(Args, OPT_fsanitize_blacklist, F, SA);
+
+ if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver3_8)
+ GenerateArg(Args, OPT_fclang_abi_compat_EQ, "3.8", SA);
+ else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver4)
+ GenerateArg(Args, OPT_fclang_abi_compat_EQ, "4.0", SA);
+ else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver6)
+ GenerateArg(Args, OPT_fclang_abi_compat_EQ, "6.0", SA);
+ else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver7)
+ GenerateArg(Args, OPT_fclang_abi_compat_EQ, "7.0", SA);
+ else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver9)
+ GenerateArg(Args, OPT_fclang_abi_compat_EQ, "9.0", SA);
+ else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver11)
+ GenerateArg(Args, OPT_fclang_abi_compat_EQ, "11.0", SA);
+
+ if (Opts.getSignReturnAddressScope() ==
+ LangOptions::SignReturnAddressScopeKind::All)
+ GenerateArg(Args, OPT_msign_return_address_EQ, "all", SA);
+ else if (Opts.getSignReturnAddressScope() ==
+ LangOptions::SignReturnAddressScopeKind::NonLeaf)
+ GenerateArg(Args, OPT_msign_return_address_EQ, "non-leaf", SA);
+
+ if (Opts.getSignReturnAddressKey() ==
+ LangOptions::SignReturnAddressKeyKind::BKey)
+ GenerateArg(Args, OPT_msign_return_address_key_EQ, "b_key", SA);
}
-bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
- InputKind IK, const llvm::Triple &T,
- std::vector<std::string> &Includes,
- DiagnosticsEngine &Diags) {
+bool CompilerInvocation::ParseLangArgsImpl(LangOptions &Opts, ArgList &Args,
+ InputKind IK, const llvm::Triple &T,
+ std::vector<std::string> &Includes,
+ DiagnosticsEngine &Diags) {
unsigned NumErrorsBefore = Diags.getNumErrors();
// FIXME: Cleanup per-file based stuff.
@@ -2868,6 +3087,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
}
}
+ // Check if -fopenmp is specified and set default version to 5.0.
+ Opts.OpenMP = Args.hasArg(OPT_fopenmp) ? 50 : 0;
// Check if -fopenmp-simd is specified.
bool IsSimdSpecified =
Args.hasFlag(options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd,
@@ -3011,6 +3232,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
// Parse -fsanitize= arguments.
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
+ Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
std::vector<std::string> systemBlacklists =
Args.getAllArgValues(OPT_fsanitize_system_blacklist);
Opts.SanitizerBlacklistFiles.insert(Opts.SanitizerBlacklistFiles.end(),
@@ -3087,6 +3309,55 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
return Success && Diags.getNumErrors() == NumErrorsBefore;
}
+bool CompilerInvocation::ParseLangArgs(CompilerInvocation &Res,
+ LangOptions &Opts,
+ llvm::opt::ArgList &Args, InputKind IK,
+ const llvm::Triple &T,
+ std::vector<std::string> &Includes,
+ DiagnosticsEngine &Diags) {
+ auto DummyOpts = std::make_shared<LangOptions>();
+
+ // We need to work around inconsistencies related to optimization flags. Their
+ // primary consumer is CodeGenOptions. However, the LangOptions parser also
+ // queries them, which means RoundTrip expects us to generate them. We don't
+ // want to do it in GenerateLangArgs, because it should eventually be the
+ // responsibility of GenerateCodeGenArgs. Until we start doing one big
+ // round-trip, let's do it here.
+ //
+ // Our parser always queries OPT_O_Group. When given -O1, -O2 or -O3, it also
+ // queries OPT_O. To ensure RoundTrip consistently considers us responsible
+ // for generating all of them, we ensure to proactively query them all.
+
+ return RoundTrip(
+ [IK, &T, &Includes](CompilerInvocation &Res, ArgList &Args,
+ DiagnosticsEngine &Diags) {
+ // Proactively query all optimization flags.
+ Args.getLastArg(OPT_O0, OPT_O4, OPT_O, OPT_Ofast);
+ return ParseLangArgsImpl(*Res.getLangOpts(), Args, IK, T, Includes,
+ Diags);
+ },
+ [&T, &Args](CompilerInvocation &Res,
+ SmallVectorImpl<const char *> &GenArgs, StringAllocator SA) {
+ GenerateLangArgs(*Res.getLangOpts(), GenArgs, SA, T);
+ // Generate all optimization flags we queried.
+ if (Arg *A = Args.getLastArg(OPT_O_Group)) {
+ OptSpecifier Opt = A->getOption().getID();
+
+ if (A->getNumValues() > 0)
+ GenerateArg(GenArgs, Opt, A->getValues().back(), SA);
+ else
+ GenerateArg(GenArgs, Opt, SA);
+ }
+
+ // We also queried -fcf-protection, but don't have enough information to
+ // generate it. Eventually, it will be generated from CodeGenOptions.
+ if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ))
+ GenerateArg(GenArgs, OPT_fcf_protection_EQ, A->getValue(), SA);
+ },
+ [&DummyOpts](CompilerInvocation &Res) { Res.LangOpts.swap(DummyOpts); },
+ Res, Args, Diags, "LangOptions");
+}
+
static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
switch (Action) {
case frontend::ASTDeclList:
@@ -3425,7 +3696,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
} else {
// Other LangOpts are only initialized when the input is not AST or LLVM IR.
// FIXME: Should we really be calling this for an Language::Asm input?
- Success &= ParseLangArgs(LangOpts, Args, DashX, T,
+ Success &= ParseLangArgs(Res, LangOpts, Args, DashX, T,
Res.getPreprocessorOpts().Includes, Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
LangOpts.ObjCExceptions = 1;
@@ -3612,19 +3883,19 @@ void CompilerInvocation::generateCC1CommandLine(
EXTRACTOR, TABLE_INDEX)
#define DIAG_OPTION_WITH_MARSHALLING OPTION_WITH_MARSHALLING
-#define LANG_OPTION_WITH_MARSHALLING OPTION_WITH_MARSHALLING
#define CODEGEN_OPTION_WITH_MARSHALLING OPTION_WITH_MARSHALLING
#include "clang/Driver/Options.inc"
#undef CODEGEN_OPTION_WITH_MARSHALLING
-#undef LANG_OPTION_WITH_MARSHALLING
#undef DIAG_OPTION_WITH_MARSHALLING
#undef OPTION_WITH_MARSHALLING
+ llvm::Triple T(TargetOpts->Triple);
+
GenerateAnalyzerArgs(*AnalyzerOpts, Args, SA);
GenerateHeaderSearchArgs(*HeaderSearchOpts, Args, SA);
- GenerateLangArgs(*LangOpts, Args, SA);
+ GenerateLangArgs(*LangOpts, Args, SA, T);
GeneratePreprocessorArgs(*PreprocessorOpts, Args, SA, *LangOpts,
FrontendOpts, CodeGenOpts);
}