diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -274,6 +274,9 @@ BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking") LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants") LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math") +BENIGN_LANGOPT(CLNoSignedZero , 1, 0, "Permit Floating Point optimization without regard to signed zeros") +COMPATIBLE_LANGOPT(CLUnsafeMath , 1, 0, "Unsafe Floating Point Math") +COMPATIBLE_LANGOPT(CLFiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") /// FP_CONTRACT mode (on/off/fast). BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contraction type") COMPATIBLE_LANGOPT(ExpStrictFP, 1, false, "Enable experimental strict floating point") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -245,9 +245,11 @@ // Args.hasArg(OPT_ffoo) is used to check that the flag is enabled. // This is useful if the option is usually disabled. multiclass OptInFFlag flags=[]> { + string help="", list flags=[], code keypath="", + DefaultAnyOf defaults = DefaultAnyOf<[]>> { def f#NAME : Flag<["-"], "f"#name>, Flags, - Group, HelpText; + Group, HelpText, + MarshallingInfoFlag; def fno_#NAME : Flag<["-"], "fno-"#name>, Flags, Group, HelpText; } @@ -255,11 +257,13 @@ // A boolean option which is opt-out in CC1. The negative option exists in CC1 and // Args.hasArg(OPT_fno_foo) is used to check that the flag is disabled. multiclass OptOutFFlag flags=[]> { + string help="", list flags=[], code keypath="", + DefaultAnyOf defaults = DefaultAnyOf<[]>> { def f#NAME : Flag<["-"], "f"#name>, Flags, Group, HelpText; def fno_#NAME : Flag<["-"], "fno-"#name>, Flags, - Group, HelpText; + Group, HelpText, + MarshallingInfoFlag; } ///////// @@ -563,27 +567,36 @@ def cl_strict_aliasing : Flag<["-"], "cl-strict-aliasing">, Group, Flags<[CC1Option]>, HelpText<"OpenCL only. This option is added for compatibility with OpenCL 1.0.">; def cl_single_precision_constant : Flag<["-"], "cl-single-precision-constant">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Treat double precision floating-point constant as single precision constant.">; + HelpText<"OpenCL only. Treat double precision floating-point constant as single precision constant.">, + MarshallingInfoFlag<"LangOpts->SinglePrecisionConstants">; def cl_finite_math_only : Flag<["-"], "cl-finite-math-only">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">; + HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">, + MarshallingInfoFlag<"LangOpts->CLFiniteMathOnly">; def cl_kernel_arg_info : Flag<["-"], "cl-kernel-arg-info">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Generate kernel argument metadata.">; + HelpText<"OpenCL only. Generate kernel argument metadata.">, + MarshallingInfoFlag<"CodeGenOpts.EmitOpenCLArgMetadata">; def cl_unsafe_math_optimizations : Flag<["-"], "cl-unsafe-math-optimizations">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable.">; + HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable.">, + MarshallingInfoFlag<"LangOpts->CLUnsafeMath">; def cl_fast_relaxed_math : Flag<["-"], "cl-fast-relaxed-math">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Sets -cl-finite-math-only and -cl-unsafe-math-optimizations, and defines __FAST_RELAXED_MATH__.">; + HelpText<"OpenCL only. Sets -cl-finite-math-only and -cl-unsafe-math-optimizations, and defines __FAST_RELAXED_MATH__.">, + MarshallingInfoFlag<"LangOpts->FastRelaxedMath">; def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Allow use of less precise MAD computations in the generated binary.">; + HelpText<"OpenCL only. Allow use of less precise MAD computations in the generated binary.">, + MarshallingInfoFlag<"CodeGenOpts.LessPreciseFPMAD", DefaultAnyOf<[cl_unsafe_math_optimizations, cl_fast_relaxed_math]>>; def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">; + HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">, + MarshallingInfoFlag<"LangOpts->CLNoSignedZero">; def cl_std_EQ : Joined<["-"], "cl-std=">, Group, Flags<[CC1Option]>, HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0,cl3.0,CL3.0,clc++,CLC++">; def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group, HelpText<"OpenCL only. Allow denormals to be flushed to zero.">; def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Specify that single precision floating-point divide and sqrt used in the program source are correctly rounded.">; + HelpText<"OpenCL only. Specify that single precision floating-point divide and sqrt used in the program source are correctly rounded.">, + MarshallingInfoFlag<"CodeGenOpts.CorrectlyRoundedDivSqrt">; def cl_uniform_work_group_size : Flag<["-"], "cl-uniform-work-group-size">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL only. Defines that the global work-size be a multiple of the work-group size specified to clEnqueueNDRangeKernel">; + HelpText<"OpenCL only. Defines that the global work-size be a multiple of the work-group size specified to clEnqueueNDRangeKernel">, + MarshallingInfoFlag<"CodeGenOpts.UniformWGSize">; def client__name : JoinedOrSeparate<["-"], "client_name">; def combine : Flag<["-", "--"], "combine">, Flags<[NoXarchOption, Unsupported]>; def compatibility__version : JoinedOrSeparate<["-"], "compatibility_version">; @@ -890,7 +903,7 @@ def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group; def fansi_escape_codes : Flag<["-"], "fansi-escape-codes">, Group, Flags<[CoreOption, CC1Option]>, HelpText<"Use ANSI escape codes for diagnostics">, - MarshallingInfoFlag<"DiagnosticOpts->UseANSIEscapeCodes", "false">; + MarshallingInfoFlag<"DiagnosticOpts->UseANSIEscapeCodes">; def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Group, Flags<[CC1Option]>, HelpText<"Treat each comma separated argument in as a documentation comment block command">, MetaVarName<"">; @@ -1002,7 +1015,11 @@ HelpText<"Controls the semantics of floating-point calculations.">; def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group, Flags<[CC1Option]>, HelpText<"Specifies the exception behavior of floating-point operations.">; -defm fast_math : OptInFFlag<"fast-math", "Allow aggressive, lossy floating-point optimizations">; +defm fast_math : OptInFFlag<"fast-math", "Allow aggressive, lossy floating-point optimizations", "", "", [], + "LangOpts->FastMath", DefaultAnyOf<[cl_fast_relaxed_math]>>; +def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">, Flags<[CC1Option]>, + HelpText<"Allow unsafe floating-point math optimizations which may decrease precision">, + MarshallingInfoFlag<"LangOpts->UnsafeFPMath", DefaultAnyOf<[cl_unsafe_math_optimizations, ffast_math]>>; defm math_errno : OptInFFlag<"math-errno", "Require math functions to indicate errors by setting errno">; def fbracket_depth_EQ : Joined<["-"], "fbracket-depth=">, Group, Flags<[CoreOption]>; def fsignaling_math : Flag<["-"], "fsignaling-math">, Group; @@ -1215,16 +1232,14 @@ Group; def fassociative_math : Flag<["-"], "fassociative-math">, Group; def fno_associative_math : Flag<["-"], "fno-associative-math">, Group; -def freciprocal_math : - Flag<["-"], "freciprocal-math">, Group, Flags<[CC1Option]>, - HelpText<"Allow division operations to be reassociated">; -def fno_reciprocal_math : Flag<["-"], "fno-reciprocal-math">, Group; -def ffinite_math_only : Flag<["-"], "ffinite-math-only">, Group, Flags<[CC1Option]>; -def fno_finite_math_only : Flag<["-"], "fno-finite-math-only">, Group; -def fsigned_zeros : Flag<["-"], "fsigned-zeros">, Group; -def fno_signed_zeros : - Flag<["-"], "fno-signed-zeros">, Group, Flags<[CC1Option]>, - HelpText<"Allow optimizations that ignore the sign of floating point zeros">; +defm reciprocal_math : OptInFFlag<"reciprocal-math", "Allow division operations to be reassociated", "", "", [], + "LangOpts->AllowRecip", DefaultAnyOf<[menable_unsafe_fp_math]>>; +def fapprox_func : Flag<["-"], "fapprox-func">, Group, Flags<[CC1Option, NoDriverOption]>, + MarshallingInfoFlag<"LangOpts->ApproxFunc", DefaultAnyOf<[menable_unsafe_fp_math]>>; +defm finite_math_only : OptInFFlag<"finite-math-only", "", "", "", [], + "LangOpts->FiniteMathOnly", DefaultAnyOf<[cl_finite_math_only, ffast_math]>>; +defm signed_zeros : OptOutFFlag<"signed-zeros", "Allow optimizations that ignore the sign of floating point zeros", "", "", [], + "LangOpts->NoSignedZero", DefaultAnyOf<[cl_no_signed_zeros, menable_unsafe_fp_math]>>; def fhonor_nans : Flag<["-"], "fhonor-nans">, Group; def fno_honor_nans : Flag<["-"], "fno-honor-nans">, Group; def fhonor_infinities : Flag<["-"], "fhonor-infinities">, Group; @@ -3847,14 +3862,14 @@ def mdisable_tail_calls : Flag<["-"], "mdisable-tail-calls">, HelpText<"Disable tail call optimization, keeping the call stack accurate">; def menable_no_infinities : Flag<["-"], "menable-no-infs">, - HelpText<"Allow optimization to assume there are no infinities.">; + HelpText<"Allow optimization to assume there are no infinities.">, + MarshallingInfoFlag<"LangOpts->NoHonorInfs", DefaultAnyOf<[ffinite_math_only]>>; def menable_no_nans : Flag<["-"], "menable-no-nans">, - HelpText<"Allow optimization to assume there are no NaNs.">; -def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">, - HelpText<"Allow unsafe floating-point math optimizations which may decrease " - "precision">; + HelpText<"Allow optimization to assume there are no NaNs.">, + MarshallingInfoFlag<"LangOpts->NoHonorNaNs", DefaultAnyOf<[ffinite_math_only]>>; def mreassociate : Flag<["-"], "mreassociate">, - HelpText<"Allow reassociation transformations for floating-point instructions">; + HelpText<"Allow reassociation transformations for floating-point instructions">, + MarshallingInfoFlag<"LangOpts->AllowFPReassoc", DefaultAnyOf<[menable_unsafe_fp_math]>>; def mabi_EQ_ieeelongdouble : Flag<["-"], "mabi=ieeelongdouble">, HelpText<"Use IEEE 754 quadruple-precision for long double">; def mfloat_abi : Separate<["-"], "mfloat-abi">, @@ -4405,7 +4420,7 @@ def fmodules_strict_context_hash : Flag<["-"], "fmodules-strict-context-hash">, HelpText<"Enable hashing of all compiler options that could impact the " "semantics of a module in an implicit build">, - MarshallingInfoFlag<"HeaderSearchOpts->ModulesStrictContextHash", "false">; + MarshallingInfoFlag<"HeaderSearchOpts->ModulesStrictContextHash">; def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"">, HelpText<"Add directory to the C SYSTEM include search path">; def objc_isystem : JoinedOrSeparate<["-"], "objc-isystem">, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -941,15 +941,8 @@ Opts.NoEscapingBlockTailCalls = Args.hasArg(OPT_fno_escaping_block_tail_calls); Opts.FloatABI = std::string(Args.getLastArgValue(OPT_mfloat_abi)); - Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable) || - Args.hasArg(OPT_cl_unsafe_math_optimizations) || - Args.hasArg(OPT_cl_fast_relaxed_math); Opts.LimitFloatPrecision = std::string(Args.getLastArgValue(OPT_mlimit_float_precision)); - Opts.CorrectlyRoundedDivSqrt = - Args.hasArg(OPT_cl_fp32_correctly_rounded_divide_sqrt); - Opts.UniformWGSize = - Args.hasArg(OPT_cl_uniform_work_group_size); Opts.Reciprocals = Args.getAllArgValues(OPT_mrecip_EQ); Opts.StrictFloatCastOverflow = !Args.hasArg(OPT_fno_strict_float_cast_overflow); @@ -1161,7 +1154,6 @@ Opts.MNopMCount = Args.hasArg(OPT_mnop_mcount); Opts.RecordMCount = Args.hasArg(OPT_mrecord_mcount); Opts.PackedStack = Args.hasArg(OPT_mpacked_stack); - Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { StringRef Name = A->getValue(); @@ -3061,8 +3053,6 @@ Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts); Opts.SpellChecking = !Args.hasArg(OPT_fno_spell_checking); Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align); - Opts.SinglePrecisionConstants = Args.hasArg(OPT_cl_single_precision_constant); - Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math); if (Opts.FastRelaxedMath) Opts.setDefaultFPContractMode(LangOptions::FPM_Fast); Opts.HexagonQdsp6Compat = Args.hasArg(OPT_mqdsp6_compat); @@ -3330,47 +3320,6 @@ if (InlineArg->getOption().matches(options::OPT_fno_inline)) Opts.NoInlineDefine = true; - Opts.FastMath = - Args.hasArg(OPT_ffast_math) || Args.hasArg(OPT_cl_fast_relaxed_math); - Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only) || - Args.hasArg(OPT_ffast_math) || - Args.hasArg(OPT_cl_finite_math_only) || - Args.hasArg(OPT_cl_fast_relaxed_math); - Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) || - Args.hasArg(OPT_ffast_math) || - Args.hasArg(OPT_cl_unsafe_math_optimizations) || - Args.hasArg(OPT_cl_fast_relaxed_math); - Opts.AllowFPReassoc = Args.hasArg(OPT_mreassociate) || - Args.hasArg(OPT_menable_unsafe_fp_math) || - Args.hasArg(OPT_ffast_math) || - Args.hasArg(OPT_cl_unsafe_math_optimizations) || - Args.hasArg(OPT_cl_fast_relaxed_math); - Opts.NoHonorNaNs = - Args.hasArg(OPT_menable_no_nans) || Args.hasArg(OPT_ffinite_math_only) || - Args.hasArg(OPT_ffast_math) || Args.hasArg(OPT_cl_finite_math_only) || - Args.hasArg(OPT_cl_fast_relaxed_math); - Opts.NoHonorInfs = Args.hasArg(OPT_menable_no_infinities) || - Args.hasArg(OPT_ffinite_math_only) || - Args.hasArg(OPT_ffast_math) || - Args.hasArg(OPT_cl_finite_math_only) || - Args.hasArg(OPT_cl_fast_relaxed_math); - Opts.NoSignedZero = Args.hasArg(OPT_fno_signed_zeros) || - Args.hasArg(OPT_menable_unsafe_fp_math) || - Args.hasArg(OPT_ffast_math) || - Args.hasArg(OPT_cl_no_signed_zeros) || - Args.hasArg(OPT_cl_unsafe_math_optimizations) || - Args.hasArg(OPT_cl_fast_relaxed_math); - Opts.AllowRecip = Args.hasArg(OPT_freciprocal_math) || - Args.hasArg(OPT_menable_unsafe_fp_math) || - Args.hasArg(OPT_ffast_math) || - Args.hasArg(OPT_cl_unsafe_math_optimizations) || - Args.hasArg(OPT_cl_fast_relaxed_math); - // Currently there's no clang option to enable this individually - Opts.ApproxFunc = Args.hasArg(OPT_menable_unsafe_fp_math) || - Args.hasArg(OPT_ffast_math) || - Args.hasArg(OPT_cl_unsafe_math_optimizations) || - Args.hasArg(OPT_cl_fast_relaxed_math); - if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { StringRef Val = A->getValue(); if (Val == "fast") @@ -3777,7 +3726,7 @@ ALIAS, ALIASARGS, FLAGS, PARAM, HELPTEXT, \ METAVAR, VALUES, SPELLING, ALWAYS_EMIT, \ KEYPATH, DEFAULT_VALUE, IS_POSITIVE) \ - this->KEYPATH = Args.hasArg(OPT_##ID) && IS_POSITIVE; + this->KEYPATH = (Args.hasArg(OPT_##ID) && IS_POSITIVE) || (DEFAULT_VALUE); #define OPTION_WITH_MARSHALLING_STRING( \ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ @@ -4051,15 +4000,15 @@ ALIAS, ALIASARGS, FLAGS, PARAM, HELPTEXT, \ METAVAR, VALUES, SPELLING, ALWAYS_EMIT, \ KEYPATH, DEFAULT_VALUE, IS_POSITIVE) \ - if ((FLAGS) & options::CC1Option && \ - (ALWAYS_EMIT || this->KEYPATH != DEFAULT_VALUE)) \ + if ((FLAGS) & options::CC1Option && \ + (ALWAYS_EMIT || this->KEYPATH != (DEFAULT_VALUE))) \ Args.push_back(SPELLING); #define OPTION_WITH_MARSHALLING_STRING( \ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR, VALUES, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ NORMALIZER_RET_TY, NORMALIZER, DENORMALIZER, TABLE_INDEX) \ - if (((FLAGS) & options::CC1Option) && \ + if (((FLAGS) & options::CC1Option) && \ (ALWAYS_EMIT || this->KEYPATH != DEFAULT_VALUE)) { \ if (Option::KIND##Class == Option::SeparateClass) { \ Args.push_back(SPELLING); \ diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -37,6 +37,25 @@ : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions())) {} }; +TEST(OptsPopulationTest, CanPopulateOptsWithImpliedFlags) { + const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations"}; + + auto Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions()); + + CompilerInvocation CInvok; + CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + + // Explicitly provided flag. + ASSERT_EQ(CInvok.getLangOpts()->CLUnsafeMath, true); + + // Flags directly implied by explicitly provided flag. + ASSERT_EQ(CInvok.getCodeGenOpts().LessPreciseFPMAD, true); + ASSERT_EQ(CInvok.getLangOpts()->UnsafeFPMath, true); + + // Flag transitively implied by explicitly provided flag. + ASSERT_EQ(CInvok.getLangOpts()->AllowRecip, true); +} + TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineFlag) { const char *Args[] = {"clang", "-xc++", "-fmodules-strict-context-hash", "-"}; @@ -115,4 +134,20 @@ ASSERT_THAT(GeneratedArgs, Each(StrNe(RelocationModelCStr))); } +TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineImpliedFlags) { + const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations", + "-cl-mad-enable", "-menable-unsafe-fp-math"}; + + CompilerInvocation CInvok; + CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + + CInvok.generateCC1CommandLine(GeneratedArgs, *this); + + // Explicitly provided flags that were also implied by another flag are not + // generated. + ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); + ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); + ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); +} + } // anonymous namespace diff --git a/llvm/include/llvm/Option/OptParser.td b/llvm/include/llvm/Option/OptParser.td --- a/llvm/include/llvm/Option/OptParser.td +++ b/llvm/include/llvm/Option/OptParser.td @@ -144,6 +144,11 @@ // Helpers for defining marshalling information. +class DefaultAnyOf defaults> { + code DefaultValue = !foldl("false", defaults, accumulator, option, + !strconcat(accumulator, " || ", !cast(option.KeyPath))); +} + class MarshallingInfo { code KeyPath = keypath; code DefaultValue = defaultvalue; @@ -154,8 +159,8 @@ code NormalizerRetTy = normalizerretty; } -class MarshallingInfoFlag - : MarshallingInfo { +class MarshallingInfoFlag> + : MarshallingInfo { string MarshallingKind = "flag"; } diff --git a/llvm/unittests/Option/CMakeLists.txt b/llvm/unittests/Option/CMakeLists.txt --- a/llvm/unittests/Option/CMakeLists.txt +++ b/llvm/unittests/Option/CMakeLists.txt @@ -10,4 +10,5 @@ add_llvm_unittest(OptionTests OptionParsingTest.cpp + OptionMarshallingTest.cpp ) diff --git a/llvm/unittests/Option/OptionMarshallingTest.cpp b/llvm/unittests/Option/OptionMarshallingTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Option/OptionMarshallingTest.cpp @@ -0,0 +1,47 @@ +//===- unittest/Support/OptionMarshallingTest.cpp - OptParserEmitter tests ===// +// +// 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 "gtest/gtest.h" + +struct OptionWithMarshallingInfo { + const char *Name; + const char *KeyPath; + const char *DefaultValue; +}; + +static const OptionWithMarshallingInfo MarshallingTable[] = { +#define OPTION_WITH_MARSHALLING_FLAG(PREFIX_TYPE, NAME, ID, KIND, GROUP, \ + ALIAS, ALIASARGS, FLAGS, PARAM, HELPTEXT, \ + METAVAR, VALUES, SPELLING, ALWAYS_EMIT, \ + KEYPATH, DEFAULT_VALUE, IS_POSITIVE) \ + { NAME, #KEYPATH, #DEFAULT_VALUE }, +#include "Opts.inc" +#undef OPTION_WITH_MARSHALLING_FLAG +}; + +TEST(OptionMarshalling, EmittedOrderSameAsDefinitionOrder) { + ASSERT_STREQ(MarshallingTable[0].Name, "marshalled-flag-0"); + ASSERT_STREQ(MarshallingTable[1].Name, "marshalled-flag-1"); + ASSERT_STREQ(MarshallingTable[2].Name, "marshalled-flag-2"); + ASSERT_STREQ(MarshallingTable[3].Name, "marshalled-flag-3"); +} + +TEST(OptionMarshalling, EmittedSpecifiedKeyPath) { + ASSERT_STREQ(MarshallingTable[0].KeyPath, "MarshalledFlag0"); + ASSERT_STREQ(MarshallingTable[1].KeyPath, "MarshalledFlag1"); + ASSERT_STREQ(MarshallingTable[2].KeyPath, "MarshalledFlag2"); + ASSERT_STREQ(MarshallingTable[3].KeyPath, "MarshalledFlag3"); +} + +TEST(OptionMarshalling, DefaultAnyOfConstructedDisjunctionOfKeypaths) { + ASSERT_STREQ(MarshallingTable[0].DefaultValue, "false"); + ASSERT_STREQ(MarshallingTable[1].DefaultValue, "false || MarshalledFlag0"); + ASSERT_STREQ(MarshallingTable[2].DefaultValue, "false || MarshalledFlag0"); + ASSERT_STREQ(MarshallingTable[3].DefaultValue, + "false || MarshalledFlag1 || MarshalledFlag2"); +} diff --git a/llvm/unittests/Option/Opts.td b/llvm/unittests/Option/Opts.td --- a/llvm/unittests/Option/Opts.td +++ b/llvm/unittests/Option/Opts.td @@ -44,3 +44,12 @@ def Blurmpq_eq : Flag<["--"], "blurmp=">; def DashDash : Option<["--"], "", KIND_REMAINING_ARGS>; + +def marshalled_flag_0 : Flag<["-"], "marshalled-flag-0">, + MarshallingInfoFlag<"MarshalledFlag0", DefaultAnyOf<[]>>; +def marshalled_flag_1 : Flag<["-"], "marshalled-flag-1">, + MarshallingInfoFlag<"MarshalledFlag1", DefaultAnyOf<[marshalled_flag_0]>>; +def marshalled_flag_2 : Flag<["-"], "marshalled-flag-2">, + MarshallingInfoFlag<"MarshalledFlag2", DefaultAnyOf<[marshalled_flag_0]>>; +def marshalled_flag_3 : Flag<["-"], "marshalled-flag-3">, + MarshallingInfoFlag<"MarshalledFlag3", DefaultAnyOf<[marshalled_flag_1, marshalled_flag_2]>>; diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp --- a/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/llvm/utils/TableGen/OptParserEmitter.cpp @@ -435,7 +435,12 @@ OS << "nullptr"; }; - std::vector> OptsWithMarshalling; + auto IsMarshallingOption = [](const Record &R) { + return !isa(R.getValueInit("MarshallingKind")) && + !R.getValueAsString("KeyPath").empty(); + }; + + std::vector OptsWithMarshalling; for (unsigned I = 0, E = Opts.size(); I != E; ++I) { const Record &R = *Opts[I]; @@ -443,12 +448,33 @@ OS << "OPTION("; WriteOptRecordFields(OS, R); OS << ")\n"; - if (!isa(R.getValueInit("MarshallingKind"))) - OptsWithMarshalling.push_back(MarshallingKindInfo::create(R)); + if (IsMarshallingOption(R)) + OptsWithMarshalling.push_back(&R); } OS << "#endif // OPTION\n"; - for (const auto &KindInfo : OptsWithMarshalling) { + auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) { + unsigned AID = (*A)->getID(); + unsigned BID = (*B)->getID(); + + if (AID < BID) + return -1; + if (AID > BID) + return 1; + return 0; + }; + // The RecordKeeper stores records (options) in lexicographical order, and we + // have reordered the options again when generating prefix groups. We need to + // restore the original definition order of options with marshalling to honor + // the topology of the dependency graph implied by `DefaultAnyOf`. + array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(), + CmpMarshallingOpts); + + std::vector> MarshallingKindInfos; + for (const auto *R : OptsWithMarshalling) + MarshallingKindInfos.push_back(MarshallingKindInfo::create(*R)); + + for (const auto &KindInfo : MarshallingKindInfos) { OS << "#ifdef " << KindInfo->MacroName << "\n"; OS << KindInfo->MacroName << "("; WriteOptRecordFields(OS, KindInfo->R); @@ -463,7 +489,7 @@ OS << "\n"; OS << MarshallingStringInfo::ValueTablePreamble; std::vector ValueTableNames; - for (const auto &KindInfo : OptsWithMarshalling) + for (const auto &KindInfo : MarshallingKindInfos) if (auto MaybeValueTableName = KindInfo->emitValueTable(OS)) ValueTableNames.push_back(*MaybeValueTableName);