diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -450,6 +450,20 @@ LangOptions(); + /// Set language defaults for the given input language and + /// language standard in the given LangOptions object. + /// + /// \param Opts - The LangOptions object to set up. + /// \param Lang - The input language. + /// \param T - The target triple. + /// \param Includes - If the language requires extra headers to be implicitly + /// included, they will be appended to this list. + /// \param LangStd - The input language standard. + static void + setLangDefaults(LangOptions &Opts, Language Lang, const llvm::Triple &T, + std::vector &Includes, + LangStandard::Kind LangStd = LangStandard::lang_unspecified); + // Define accessors/mutators for language options of enumeration type. #define LANGOPT(Name, Bits, Default, Description) #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ diff --git a/clang/include/clang/Basic/LangStandard.h b/clang/include/clang/Basic/LangStandard.h --- a/clang/include/clang/Basic/LangStandard.h +++ b/clang/include/clang/Basic/LangStandard.h @@ -12,6 +12,10 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" +namespace llvm { +class Triple; +} + namespace clang { /// The language for the input, used to select and validate the language @@ -134,10 +138,14 @@ bool isOpenCL() const { return Flags & OpenCL; } static Kind getLangKind(StringRef Name); + static const LangStandard &getLangStandardForKind(Kind K); static const LangStandard *getLangStandardForName(StringRef Name); }; +LangStandard::Kind getDefaultLanguageStandard(clang::Language Lang, + const llvm::Triple &T); + } // end namespace clang #endif diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -219,19 +219,6 @@ /// executable), for finding the builtin compiler path. static std::string GetResourcesPath(const char *Argv0, void *MainAddr); - /// Set language defaults for the given input language and - /// language standard in the given LangOptions object. - /// - /// \param Opts - The LangOptions object to set up. - /// \param IK - The input language. - /// \param T - The target triple. - /// \param Includes - The affected list of included files. - /// \param LangStd - The input language standard. - static void - setLangDefaults(LangOptions &Opts, InputKind IK, const llvm::Triple &T, - std::vector &Includes, - LangStandard::Kind LangStd = LangStandard::lang_unspecified); - /// Retrieve a module hash string that is suitable for uniquely /// identifying the conditions under which the module was built. std::string getModuleHash() const; diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -78,6 +78,124 @@ return Result; } +void LangOptions::setLangDefaults(LangOptions &Opts, Language Lang, + const llvm::Triple &T, + std::vector &Includes, + LangStandard::Kind LangStd) { + // Set some properties which depend solely on the input kind; it would be nice + // to move these to the language standard, and have the driver resolve the + // input kind + language standard. + // + // FIXME: Perhaps a better model would be for a single source file to have + // multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std) + // simultaneously active? + if (Lang == Language::Asm) { + Opts.AsmPreprocessor = 1; + } else if (Lang == Language::ObjC || Lang == Language::ObjCXX) { + Opts.ObjC = 1; + } + + if (LangStd == LangStandard::lang_unspecified) + LangStd = getDefaultLanguageStandard(Lang, T); + const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); + Opts.LangStd = LangStd; + Opts.LineComment = Std.hasLineComments(); + Opts.C99 = Std.isC99(); + Opts.C11 = Std.isC11(); + Opts.C17 = Std.isC17(); + Opts.C2x = Std.isC2x(); + Opts.CPlusPlus = Std.isCPlusPlus(); + Opts.CPlusPlus11 = Std.isCPlusPlus11(); + Opts.CPlusPlus14 = Std.isCPlusPlus14(); + Opts.CPlusPlus17 = Std.isCPlusPlus17(); + Opts.CPlusPlus20 = Std.isCPlusPlus20(); + Opts.CPlusPlus2b = Std.isCPlusPlus2b(); + Opts.GNUMode = Std.isGNUMode(); + Opts.GNUCVersion = 0; + Opts.HexFloats = Std.hasHexFloats(); + Opts.ImplicitInt = Std.hasImplicitInt(); + + Opts.HLSL = Lang == Language::HLSL; + + // Set OpenCL Version. + Opts.OpenCL = Std.isOpenCL(); + if (LangStd == LangStandard::lang_opencl10) + Opts.OpenCLVersion = 100; + else if (LangStd == LangStandard::lang_opencl11) + Opts.OpenCLVersion = 110; + else if (LangStd == LangStandard::lang_opencl12) + Opts.OpenCLVersion = 120; + else if (LangStd == LangStandard::lang_opencl20) + Opts.OpenCLVersion = 200; + else if (LangStd == LangStandard::lang_opencl30) + Opts.OpenCLVersion = 300; + else if (LangStd == LangStandard::lang_openclcpp10) + Opts.OpenCLCPlusPlusVersion = 100; + else if (LangStd == LangStandard::lang_openclcpp2021) + Opts.OpenCLCPlusPlusVersion = 202100; + else if (LangStd == LangStandard::lang_hlsl2015) + Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2015; + else if (LangStd == LangStandard::lang_hlsl2016) + Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2016; + else if (LangStd == LangStandard::lang_hlsl2017) + Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2017; + else if (LangStd == LangStandard::lang_hlsl2018) + Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2018; + else if (LangStd == LangStandard::lang_hlsl2021) + Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2021; + else if (LangStd == LangStandard::lang_hlsl202x) + Opts.HLSLVersion = (unsigned)LangOptions::HLSL_202x; + + // OpenCL has some additional defaults. + if (Opts.OpenCL) { + Opts.AltiVec = 0; + Opts.ZVector = 0; + Opts.setDefaultFPContractMode(LangOptions::FPM_On); + Opts.OpenCLCPlusPlus = Opts.CPlusPlus; + Opts.OpenCLPipes = Opts.getOpenCLCompatibleVersion() == 200; + Opts.OpenCLGenericAddressSpace = Opts.getOpenCLCompatibleVersion() == 200; + + // Include default header file for OpenCL. + if (Opts.IncludeDefaultHeader) { + if (Opts.DeclareOpenCLBuiltins) { + // Only include base header file for builtin types and constants. + Includes.push_back("opencl-c-base.h"); + } else { + Includes.push_back("opencl-c.h"); + } + } + } + + Opts.HIP = Lang == Language::HIP; + Opts.CUDA = Lang == Language::CUDA || Opts.HIP; + if (Opts.HIP) { + // HIP toolchain does not support 'Fast' FPOpFusion in backends since it + // fuses multiplication/addition instructions without contract flag from + // device library functions in LLVM bitcode, which causes accuracy loss in + // certain math functions, e.g. tan(-1e20) becomes -0.933 instead of 0.8446. + // For device library functions in bitcode to work, 'Strict' or 'Standard' + // FPOpFusion options in backends is needed. Therefore 'fast-honor-pragmas' + // FP contract option is used to allow fuse across statements in frontend + // whereas respecting contract flag in backend. + Opts.setDefaultFPContractMode(LangOptions::FPM_FastHonorPragmas); + } else if (Opts.CUDA) { + if (T.isSPIRV()) { + // Emit OpenCL version metadata in LLVM IR when targeting SPIR-V. + Opts.OpenCLVersion = 200; + } + // Allow fuse across statements disregarding pragmas. + Opts.setDefaultFPContractMode(LangOptions::FPM_Fast); + } + + Opts.RenderScript = Lang == Language::RenderScript; + + // OpenCL, C++ and C2x have bool, true, false keywords. + Opts.Bool = Opts.OpenCL || Opts.CPlusPlus || Opts.C2x; + + // OpenCL has half keyword + Opts.Half = Opts.OpenCL; +} + FPOptions FPOptions::defaultWithoutTrailingStorage(const LangOptions &LO) { FPOptions result(LO); return result; diff --git a/clang/lib/Basic/LangStandards.cpp b/clang/lib/Basic/LangStandards.cpp --- a/clang/lib/Basic/LangStandards.cpp +++ b/clang/lib/Basic/LangStandards.cpp @@ -8,6 +8,7 @@ #include "clang/Basic/LangStandard.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -42,4 +43,47 @@ return &getLangStandardForKind(K); } - +LangStandard::Kind clang::getDefaultLanguageStandard(clang::Language Lang, + const llvm::Triple &T) { + switch (Lang) { + case Language::Unknown: + case Language::LLVM_IR: + llvm_unreachable("Invalid input kind!"); + case Language::OpenCL: + return LangStandard::lang_opencl12; + case Language::OpenCLCXX: + return LangStandard::lang_openclcpp10; + case Language::CUDA: + return LangStandard::lang_cuda; + case Language::Asm: + case Language::C: +#if defined(CLANG_DEFAULT_STD_C) + return CLANG_DEFAULT_STD_C; +#else + // The PS4 uses C99 as the default C standard. + if (T.isPS4()) + return LangStandard::lang_gnu99; + return LangStandard::lang_gnu17; +#endif + case Language::ObjC: +#if defined(CLANG_DEFAULT_STD_C) + return CLANG_DEFAULT_STD_C; +#else + return LangStandard::lang_gnu11; +#endif + case Language::CXX: + case Language::ObjCXX: +#if defined(CLANG_DEFAULT_STD_CXX) + return CLANG_DEFAULT_STD_CXX; +#else + return LangStandard::lang_gnucxx14; +#endif + case Language::RenderScript: + return LangStandard::lang_c99; + case Language::HIP: + return LangStandard::lang_hip; + case Language::HLSL: + return LangStandard::lang_hlsl2021; + } + llvm_unreachable("unhandled Language kind!"); +} 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 @@ -3173,178 +3173,6 @@ return Diags.getNumErrors() == NumErrorsBefore; } -void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, - const llvm::Triple &T, - std::vector &Includes, - LangStandard::Kind LangStd) { - // Set some properties which depend solely on the input kind; it would be nice - // to move these to the language standard, and have the driver resolve the - // input kind + language standard. - // - // FIXME: Perhaps a better model would be for a single source file to have - // multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std) - // simultaneously active? - if (IK.getLanguage() == Language::Asm) { - Opts.AsmPreprocessor = 1; - } else if (IK.isObjectiveC()) { - Opts.ObjC = 1; - } - - if (LangStd == LangStandard::lang_unspecified) { - // Based on the base language, pick one. - switch (IK.getLanguage()) { - case Language::Unknown: - case Language::LLVM_IR: - llvm_unreachable("Invalid input kind!"); - case Language::OpenCL: - LangStd = LangStandard::lang_opencl12; - break; - case Language::OpenCLCXX: - LangStd = LangStandard::lang_openclcpp10; - break; - case Language::CUDA: - LangStd = LangStandard::lang_cuda; - break; - case Language::Asm: - case Language::C: -#if defined(CLANG_DEFAULT_STD_C) - LangStd = CLANG_DEFAULT_STD_C; -#else - // The PS4 uses C99 as the default C standard. - if (T.isPS4()) - LangStd = LangStandard::lang_gnu99; - else - LangStd = LangStandard::lang_gnu17; -#endif - break; - case Language::ObjC: -#if defined(CLANG_DEFAULT_STD_C) - LangStd = CLANG_DEFAULT_STD_C; -#else - LangStd = LangStandard::lang_gnu11; -#endif - break; - case Language::CXX: - case Language::ObjCXX: -#if defined(CLANG_DEFAULT_STD_CXX) - LangStd = CLANG_DEFAULT_STD_CXX; -#else - LangStd = LangStandard::lang_gnucxx14; -#endif - break; - case Language::RenderScript: - LangStd = LangStandard::lang_c99; - break; - case Language::HIP: - LangStd = LangStandard::lang_hip; - break; - case Language::HLSL: - LangStd = LangStandard::lang_hlsl2021; - break; - } - } - - const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); - Opts.LangStd = LangStd; - Opts.LineComment = Std.hasLineComments(); - Opts.C99 = Std.isC99(); - Opts.C11 = Std.isC11(); - Opts.C17 = Std.isC17(); - Opts.C2x = Std.isC2x(); - Opts.CPlusPlus = Std.isCPlusPlus(); - Opts.CPlusPlus11 = Std.isCPlusPlus11(); - Opts.CPlusPlus14 = Std.isCPlusPlus14(); - Opts.CPlusPlus17 = Std.isCPlusPlus17(); - Opts.CPlusPlus20 = Std.isCPlusPlus20(); - Opts.CPlusPlus2b = Std.isCPlusPlus2b(); - Opts.GNUMode = Std.isGNUMode(); - Opts.GNUCVersion = 0; - Opts.HexFloats = Std.hasHexFloats(); - Opts.ImplicitInt = Std.hasImplicitInt(); - Opts.WChar = Std.isCPlusPlus(); - Opts.Digraphs = Std.hasDigraphs(); - - Opts.HLSL = IK.getLanguage() == Language::HLSL; - - // Set OpenCL Version. - Opts.OpenCL = Std.isOpenCL(); - if (LangStd == LangStandard::lang_opencl10) - Opts.OpenCLVersion = 100; - else if (LangStd == LangStandard::lang_opencl11) - Opts.OpenCLVersion = 110; - else if (LangStd == LangStandard::lang_opencl12) - Opts.OpenCLVersion = 120; - else if (LangStd == LangStandard::lang_opencl20) - Opts.OpenCLVersion = 200; - else if (LangStd == LangStandard::lang_opencl30) - Opts.OpenCLVersion = 300; - else if (LangStd == LangStandard::lang_openclcpp10) - Opts.OpenCLCPlusPlusVersion = 100; - else if (LangStd == LangStandard::lang_openclcpp2021) - Opts.OpenCLCPlusPlusVersion = 202100; - else if (LangStd == LangStandard::lang_hlsl2015) - Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2015; - else if (LangStd == LangStandard::lang_hlsl2016) - Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2016; - else if (LangStd == LangStandard::lang_hlsl2017) - Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2017; - else if (LangStd == LangStandard::lang_hlsl2018) - Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2018; - else if (LangStd == LangStandard::lang_hlsl2021) - Opts.HLSLVersion = (unsigned)LangOptions::HLSL_2021; - else if (LangStd == LangStandard::lang_hlsl202x) - Opts.HLSLVersion = (unsigned)LangOptions::HLSL_202x; - - // OpenCL has some additional defaults. - if (Opts.OpenCL) { - Opts.AltiVec = 0; - Opts.ZVector = 0; - Opts.setDefaultFPContractMode(LangOptions::FPM_On); - Opts.OpenCLCPlusPlus = Opts.CPlusPlus; - Opts.OpenCLPipes = Opts.getOpenCLCompatibleVersion() == 200; - Opts.OpenCLGenericAddressSpace = Opts.getOpenCLCompatibleVersion() == 200; - - // Include default header file for OpenCL. - if (Opts.IncludeDefaultHeader) { - if (Opts.DeclareOpenCLBuiltins) { - // Only include base header file for builtin types and constants. - Includes.push_back("opencl-c-base.h"); - } else { - Includes.push_back("opencl-c.h"); - } - } - } - - Opts.HIP = IK.getLanguage() == Language::HIP; - Opts.CUDA = IK.getLanguage() == Language::CUDA || Opts.HIP; - if (Opts.HIP) { - // HIP toolchain does not support 'Fast' FPOpFusion in backends since it - // fuses multiplication/addition instructions without contract flag from - // device library functions in LLVM bitcode, which causes accuracy loss in - // certain math functions, e.g. tan(-1e20) becomes -0.933 instead of 0.8446. - // For device library functions in bitcode to work, 'Strict' or 'Standard' - // FPOpFusion options in backends is needed. Therefore 'fast-honor-pragmas' - // FP contract option is used to allow fuse across statements in frontend - // whereas respecting contract flag in backend. - Opts.setDefaultFPContractMode(LangOptions::FPM_FastHonorPragmas); - } else if (Opts.CUDA) { - if (T.isSPIRV()) { - // Emit OpenCL version metadata in LLVM IR when targeting SPIR-V. - Opts.OpenCLVersion = 200; - } - // Allow fuse across statements disregarding pragmas. - Opts.setDefaultFPContractMode(LangOptions::FPM_Fast); - } - - Opts.RenderScript = IK.getLanguage() == Language::RenderScript; - - // OpenCL, C++ and C2x have bool, true, false keywords. - Opts.Bool = Opts.OpenCL || Opts.CPlusPlus || Opts.C2x; - - // OpenCL has half keyword - Opts.Half = Opts.OpenCL; -} - /// Check if input file kind and language standard are compatible. static bool IsInputCompatibleWithStandard(InputKind IK, const LangStandard &S) { @@ -3783,7 +3611,7 @@ Opts.IncludeDefaultHeader = Args.hasArg(OPT_finclude_default_header); Opts.DeclareOpenCLBuiltins = Args.hasArg(OPT_fdeclare_opencl_builtins); - CompilerInvocation::setLangDefaults(Opts, IK, T, Includes, LangStd); + LangOptions::setLangDefaults(Opts, IK.getLanguage(), T, Includes, LangStd); // The key paths of codegen options defined in Options.td start with // "LangOpts->". Let's provide the expected variable name and type.