//===-- cl_options.cpp ----------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "driver/cl_options.h" #include "gen/logger.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Operator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetMachine.h" namespace opts { // This vector is filled by parseCommandLine in main.cpp. llvm::SmallVector allArguments; cl::OptionCategory linkingCategory("Linking options"); // Positional options first, in order: cl::list fileList(cl::Positional, cl::desc("files")); cl::list runargs( "run", cl::desc( "Runs the resulting program, passing the remaining arguments to it"), cl::Positional, cl::PositionalEatsArgs); cl::opt invokedByLDMD("ldmd", cl::desc("Invoked by LDMD?"), cl::ZeroOrMore, cl::ReallyHidden); static cl::opt useDeprecated( cl::desc("Allow deprecated language features and symbols:"), cl::ZeroOrMore, cl::location(global.params.useDeprecated), cl::init(DIAGNOSTICinform), cl::values( clEnumValN(DIAGNOSTICoff, "d", "Silently allow deprecated features and symbols"), clEnumValN(DIAGNOSTICinform, "dw", "Issue a message when deprecated features or " "symbols are used (default)"), clEnumValN( DIAGNOSTICerror, "de", "Issue an error when deprecated features or symbols are used " "(halt compilation)"))); cl::opt compileOnly("c", cl::desc("Compile only, do not link"), cl::ZeroOrMore); static cl::opt createStaticLib("lib", cl::ZeroOrMore, cl::desc("Create static library"), cl::location(global.params.lib)); static cl::opt createSharedLib("shared", cl::desc("Create shared library (DLL)"), cl::ZeroOrMore, cl::location(global.params.dll)); cl::opt symbolVisibility( "fvisibility", cl::ZeroOrMore, cl::desc("Default visibility of symbols"), cl::init(SymbolVisibility::default_), cl::values( clEnumValN( SymbolVisibility::default_, "default", "Hidden for Windows targets without -shared, otherwise public"), clEnumValN(SymbolVisibility::hidden, "hidden", "Only export symbols marked with 'export'"), clEnumValN(SymbolVisibility::public_, "public", "Export all symbols"))); cl::opt dllimport( "dllimport", cl::ZeroOrMore, cl::location(global.params.dllimport), cl::desc("Windows only: which extern(D) global variables to dllimport " "implicitly if not defined in a root module"), cl::values( clEnumValN(DLLImport::none, "none", "None (default with -link-defaultlib-shared=false)"), clEnumValN(DLLImport::defaultLibsOnly, "defaultLibsOnly", "Only druntime/Phobos symbols (default with " "-link-defaultlib-shared and -fvisibility=hidden)."), clEnumValN(DLLImport::all, "all", "All (default with -link-defaultlib-shared and " "-fvisibility=public)"))); static cl::opt verbose("v", cl::desc("Verbose"), cl::ZeroOrMore, cl::location(global.params.v.verbose)); static cl::opt vcolumns("vcolumns", cl::desc("Print character (column) numbers in diagnostics"), cl::ZeroOrMore, cl::location(global.params.v.showColumns)); static cl::opt vgc("vgc", cl::desc("List all gc allocations including hidden ones"), cl::ZeroOrMore, cl::location(global.params.v.gc)); // Dummy data type for custom parsers where the help output shouldn't display // any value. using DummyDataType = bool; // `-vtemplates[=list-instances]` parser. struct VTemplatesParser : public cl::parser { explicit VTemplatesParser(cl::Option &O) : cl::parser(O) {} bool parse(cl::Option &O, llvm::StringRef /*ArgName*/, llvm::StringRef Arg, DummyDataType & /*Val*/) { global.params.v.templates = true; if (Arg.empty()) { return false; } if (Arg == "list-instances") { global.params.v.templatesListInstances = true; return false; } return O.error("unsupported value '" + Arg + "'"); } }; static cl::opt vtemplates( "vtemplates", cl::ZeroOrMore, cl::ValueOptional, cl::desc("List statistics on template instantiations\n" "Use -vtemplates=list-instances to additionally show all " "instantiation contexts for each template")); static cl::opt verbose_cg("v-cg", cl::desc("Verbose codegen"), cl::ZeroOrMore, cl::location(global.params.verbose_cg)); static cl::opt verbose_cg_ast("vcg-ast", cl::ZeroOrMore, cl::Hidden, cl::desc("Write AST to .cg file"), cl::location(global.params.vcg_ast)); static cl::opt errorLimit( "verrors", cl::ZeroOrMore, cl::location(global.params.v.errorLimit), cl::desc("Limit the number of error messages (0 means unlimited)")); static cl::opt showGaggedErrors("verrors-spec", cl::ZeroOrMore, cl::location(global.params.v.showGaggedErrors), cl::desc("Show errors from speculative compiles such as " "__traits(compiles,...)")); static cl::opt printErrorContext( "verrors-context", cl::ZeroOrMore, cl::location(global.params.v.printErrorContext), cl::desc( "Show error messages with the context of the erroring source line")); static cl::opt verrorStyle( "verror-style", cl::ZeroOrMore, cl::location(global.params.v.messageStyle), cl::desc( "Set the style for file/line number annotations on compiler messages"), cl::values( clEnumValN(MessageStyle::digitalmars, "digitalmars", "'file(line[,column]): message' (default)"), clEnumValN(MessageStyle::gnu, "gnu", "'file:line[:column]: message', conforming to the GNU " "standard used by gcc and clang")), cl::init(MessageStyle::digitalmars)); static cl::opt verrorSupplements("verror-supplements", cl::ZeroOrMore, cl::location(global.params.v.errorSupplementLimit), cl::desc("Limit the number of supplemental messages for " "each error (0 means unlimited)")); static cl::opt warnings( cl::desc("Warnings:"), cl::ZeroOrMore, cl::location(global.params.warnings), cl::values( clEnumValN(DIAGNOSTICerror, "w", "Enable warnings as errors (compilation will halt)"), clEnumValN(DIAGNOSTICinform, "wi", "Enable warnings as messages (compilation will continue)")), cl::init(DIAGNOSTICoff)); static cl::opt ignoreUnsupportedPragmas( "ignore", cl::desc("Ignore unsupported pragmas"), cl::ZeroOrMore, cl::location(global.params.ignoreUnsupportedPragmas)); static cl::opt cplusplus( "extern-std", cl::ZeroOrMore, cl::desc("C++ standard for name mangling compatibility"), cl::location(global.params.cplusplus), cl::values( clEnumValN(CppStdRevisionCpp98, "c++98", "Sets `__traits(getTargetInfo, \"cppStd\")` to `199711`"), clEnumValN( CppStdRevisionCpp11, "c++11", "Sets `__traits(getTargetInfo, \"cppStd\")` to `201103` (default)"), clEnumValN(CppStdRevisionCpp14, "c++14", "Sets `__traits(getTargetInfo, \"cppStd\")` to `201402`"), clEnumValN(CppStdRevisionCpp17, "c++17", "Sets `__traits(getTargetInfo, \"cppStd\")` to `201703`"), clEnumValN(CppStdRevisionCpp20, "c++20", "Sets `__traits(getTargetInfo, \"cppStd\")` to `202002`"))); static cl::opt debugInfo( cl::desc("Generating debug information:"), cl::ZeroOrMore, cl::values( clEnumValN(1, "g", "Add symbolic debug info"), clEnumValN(2, "gc", "Add symbolic debug info, optimize for non D debuggers"), clEnumValN(3, "gline-tables-only", "Add line tables only")), cl::location(global.params.symdebug), cl::init(0)); cl::opt emitDwarfDebugInfo( "gdwarf", cl::ZeroOrMore, cl::desc("Emit DWARF debuginfo (instead of CodeView) for MSVC targets")); cl::opt noAsm("noasm", cl::desc("Disallow use of inline assembler"), cl::ZeroOrMore); // Output file options cl::opt dontWriteObj("o-", cl::desc("Do not write object file"), cl::ZeroOrMore); cl::opt objectFile("of", cl::value_desc("filename"), cl::Prefix, cl::desc("Use as output file name"), cl::ZeroOrMore); cl::opt objectDir("od", cl::value_desc("directory"), cl::Prefix, cl::desc("Write object files to "), cl::ZeroOrMore); cl::opt soname("soname", cl::value_desc("soname"), cl::Hidden, cl::Prefix, cl::desc("Use as output shared library soname"), cl::ZeroOrMore); // Output format options cl::opt output_bc("output-bc", cl::desc("Write LLVM bitcode"), cl::ZeroOrMore); cl::opt output_ll("output-ll", cl::desc("Write LLVM IR"), cl::ZeroOrMore); cl::opt output_mlir("output-mlir", cl::desc("Write MLIR"), cl::ZeroOrMore); cl::opt output_s("output-s", cl::desc("Write native assembly"), cl::ZeroOrMore); cl::opt output_o("output-o", cl::ZeroOrMore, cl::desc("Write native object")); static cl::opt cleanupObjectFiles("cleanup-obj", cl::ZeroOrMore, cl::ReallyHidden, cl::desc("Remove generated object files on success"), cl::location(global.params.cleanupObjectFiles)); // DDoc options static cl::opt doDdoc("D", cl::desc("Generate documentation"), cl::location(global.params.ddoc.doOutput), cl::ZeroOrMore); cl::opt ddocDir("Dd", cl::desc("Write documentation file to "), cl::value_desc("directory"), cl::Prefix, cl::ZeroOrMore); cl::opt ddocFile("Df", cl::desc("Write documentation file to "), cl::value_desc("filename"), cl::Prefix, cl::ZeroOrMore); // Json options static cl::opt doJson("X", cl::desc("Generate JSON file"), cl::ZeroOrMore, cl::location(global.params.json.doOutput)); cl::opt jsonFile("Xf", cl::desc("Write JSON file to "), cl::value_desc("filename"), cl::Prefix, cl::ZeroOrMore); // supported by DMD, but still undocumented cl::list jsonFields("Xi", cl::ReallyHidden, cl::value_desc("field")); // Header generation options static cl::opt doHdrGen("H", cl::desc("Generate 'header' file"), cl::ZeroOrMore, cl::location(global.params.dihdr.doOutput)); cl::opt hdrDir("Hd", cl::ZeroOrMore, cl::Prefix, cl::desc("Write 'header' file to "), cl::value_desc("directory")); cl::opt hdrFile("Hf", cl::ZeroOrMore, cl::Prefix, cl::desc("Write 'header' file to "), cl::value_desc("filename")); cl::opt hdrKeepAllBodies("Hkeep-all-bodies", cl::ZeroOrMore, cl::desc("Keep all function bodies in .di files")); // C++ header generation options // `-HC[=silent|verbose]` parser. Required for defaulting to `silent`. struct HCParser : public cl::parser { explicit HCParser(cl::Option &O) : cl::parser(O) {} bool parse(cl::Option &O, llvm::StringRef /*ArgName*/, llvm::StringRef Arg, DummyDataType & /*Val*/) { global.params.cxxhdr.doOutput = true; if (Arg.empty() || Arg == "silent") { return false; } if (Arg == "verbose") { global.params.cxxhdr.fullOutput = true; return false; } return O.error("unsupported value '" + Arg + "'"); } }; static cl::opt doCxxHdrGen("HC", cl::ZeroOrMore, cl::ValueOptional, cl::desc("Generate C++ header file\n" "Use -HC=verbose to add comments for ignored " "declarations (e.g. extern(D))")); cl::opt cxxHdrDir("HCd", cl::ZeroOrMore, cl::Prefix, cl::desc("Write C++ 'header' file to "), cl::value_desc("directory")); cl::opt cxxHdrFile("HCf", cl::ZeroOrMore, cl::Prefix, cl::desc("Write C++ 'header' file to "), cl::value_desc("filename")); cl::opt mixinFile("mixin", cl::ZeroOrMore, cl::desc("Expand and save mixins to "), cl::value_desc("filename")); static cl::opt unittest("unittest", cl::ZeroOrMore, cl::desc("Compile in unit tests"), cl::location(global.params.useUnitTests)); cl::opt cacheDir("cache", cl::desc("Enable compilation cache, using to " "store cache files"), cl::value_desc("cache dir"), cl::ZeroOrMore); static StringsAdapter strImpPathStore("J", global.params.fileImppath); static cl::list stringImportPaths( "J", cl::desc("Look for string imports also in "), cl::value_desc("directory"), cl::location(strImpPathStore), cl::Prefix); static cl::opt addMain( "main", cl::ZeroOrMore, cl::location(global.params.addMain), cl::desc( "Add default main() if not present already (e.g. for unittesting)")); // -d-debug is a bit messy, it has 3 modes: // -d-debug=ident, -d-debug=level and -d-debug (without argument) // The last one represents `-d-debug=1`, so it needs some special handling: std::vector debugArgs; struct D_DebugStorage { void push_back(const std::string &str) { debugArgs.push_back(str.empty() ? "1" : str); } }; static D_DebugStorage dds; // -debug is already declared in LLVM (at least, in debug builds), // so we need to be a bit more verbose. static cl::list debugVersionsOption( "d-debug", cl::location(dds), cl::CommaSeparated, cl::ValueOptional, cl::desc("Compile in debug code >= or identified by "), cl::value_desc("level/idents")); // -version is also declared in LLVM, so again we need to be a bit more verbose. cl::list versions( "d-version", cl::CommaSeparated, cl::value_desc("level/idents"), cl::desc("Compile in version code >= or identified by ")); cl::list transitions( "transition", cl::CommaSeparated, cl::value_desc("name"), cl::desc("Help with language change identified by , use ? for list")); cl::list previews("preview", cl::CommaSeparated, cl::value_desc("name"), cl::desc("Enable an upcoming language change " "identified by , use ? for list")); cl::list reverts( "revert", cl::CommaSeparated, cl::value_desc("name"), cl::desc("Revert language change identified by , use ? for list")); cl::list linkerSwitches("L", cl::desc("Pass to the linker"), cl::value_desc("linkerflag"), cl::cat(linkingCategory), cl::Prefix); cl::list ccSwitches( "Xcc", cl::value_desc("ccflag"), cl::cat(linkingCategory), cl::desc("Pass to GCC/Clang for linking/preprocessing")); cl::list cppSwitches("P", cl::value_desc("cppflag"), cl::Prefix, cl::desc("Pass to C preprocessor")); cl::opt moduleDeps( "deps", cl::ValueOptional, cl::ZeroOrMore, cl::value_desc("filename"), cl::desc("Write module dependencies to (only imports). " "'-deps' alone prints module dependencies " "(imports/file/version/debug/lib)")); cl::opt makeDeps("makedeps", cl::ValueOptional, cl::ZeroOrMore, cl::value_desc("filename"), cl::desc("Write module dependencies in Makefile compatible format " "to /stdout (only imports)")); cl::opt m32bits("m32", cl::desc("32 bit target"), cl::ZeroOrMore); cl::opt m64bits("m64", cl::desc("64 bit target"), cl::ZeroOrMore); cl::opt mTargetTriple("mtriple", cl::ZeroOrMore, cl::desc("Override target triple")); cl::opt mABI("mabi", cl::ZeroOrMore, cl::init(""), cl::desc("The name of the ABI to be targeted from the backend")); static Strings *pModFileAliasStrings = &global.params.modFileAliasStrings; static StringsAdapter modFileAliasStringsStore("mv", pModFileAliasStrings); static cl::list modFileAliasStrings( "mv", cl::desc("Use as source file for "), cl::value_desc("="), cl::location(modFileAliasStringsStore)); cl::list includeModulePatterns( "i", cl::desc("Include imported modules in the compilation"), cl::value_desc("pattern"), cl::ValueOptional); // DMD allows omitting a value with special meaning // Storage for the dynamically created float-abi option. FloatABI::Type floatABI; static cl::opt> asserts("asserts", cl::ZeroOrMore, cl::desc("(*) Enable assertions"), cl::value_desc("bool"), cl::location(global.params.useAssert), cl::init(CHECKENABLEdefault)); static cl::opt boundsCheck( "boundscheck", cl::ZeroOrMore, cl::desc("Array bounds check"), cl::location(global.params.useArrayBounds), cl::init(CHECKENABLEdefault), cl::values(clEnumValN(CHECKENABLEoff, "off", "Disabled"), clEnumValN(CHECKENABLEsafeonly, "safeonly", "Enabled for @safe functions only"), clEnumValN(CHECKENABLEon, "on", "Enabled for all functions"))); static cl::opt> switchErrors( "switch-errors", cl::ZeroOrMore, cl::desc("(*) Enable runtime errors for unhandled switch cases"), cl::location(global.params.useSwitchError), cl::init(CHECKENABLEdefault)); static cl::opt> invariants("invariants", cl::ZeroOrMore, cl::desc("(*) Enable invariants"), cl::location(global.params.useInvariants), cl::init(CHECKENABLEdefault)); static cl::opt> preconditions("preconditions", cl::ZeroOrMore, cl::location(global.params.useIn), cl::desc("(*) Enable function preconditions"), cl::init(CHECKENABLEdefault)); static cl::opt> postconditions("postconditions", cl::ZeroOrMore, cl::location(global.params.useOut), cl::init(CHECKENABLEdefault), cl::desc("(*) Enable function postconditions")); static MultiSetter ContractsSetter(false, &global.params.useIn, &global.params.useOut, nullptr); static cl::opt> contracts("contracts", cl::ZeroOrMore, cl::location(ContractsSetter), cl::desc("(*) Enable function pre- and post-conditions")); static cl::opt checkAction( "checkaction", cl::ZeroOrMore, cl::location(global.params.checkAction), cl::desc("Action to take when an assert/boundscheck/final-switch fails"), cl::init(CHECKACTION_D), cl::values( clEnumValN(CHECKACTION_D, "D", "Usual D behavior of throwing an AssertError"), clEnumValN(CHECKACTION_C, "C", "Call the C runtime library assert failure function"), clEnumValN(CHECKACTION_halt, "halt", "Halt the program execution (very lightweight)"), clEnumValN(CHECKACTION_context, "context", "Use D assert with context information (when available)"))); static cl::opt release("release", cl::ZeroOrMore, cl::location(global.params.release), cl::desc("Compile release version, defaulting to disabled " "asserts/contracts/invariants, and bounds checks in @safe " "functions only"), cl::ValueDisallowed); cl::opt singleObj("singleobj", cl::desc("Create only a single output object file"), cl::ZeroOrMore, cl::location(global.params.oneobj)); cl::opt hashThreshold( "hash-threshold", cl::ZeroOrMore, cl::location(global.params.hashThreshold), cl::desc("Hash symbol names longer than this threshold (experimental)")); static cl::opt linkonceTemplates( cl::ZeroOrMore, cl::location(global.params.linkonceTemplates), cl::values( clEnumValN(LinkonceTemplates::yes, "linkonce-templates", "Use discardable linkonce_odr linkage for template symbols " "and lazily & recursively define all referenced " "instantiated symbols in each object file"), clEnumValN(LinkonceTemplates::aggressive, "linkonce-templates-aggressive", "Experimental, more aggressive variant"))); cl::opt disableLinkerStripDead( "disable-linker-strip-dead", cl::ZeroOrMore, cl::desc("Do not try to remove unused symbols during linking"), cl::cat(linkingCategory)); cl::opt noPLT( "fno-plt", cl::ZeroOrMore, cl::desc("Do not use the PLT to make function calls")); static cl::opt passmanager("passmanager", cl::desc("Setting the passmanager (new,legacy):"), cl::ZeroOrMore, #if LDC_LLVM_VER < 1500 cl::init(0), #else cl::init(1), #endif cl::values( clEnumValN(0, "legacy", "Use the legacy passmanager (available for LLVM14 and below) "), clEnumValN(1, "new", "Use the new passmanager (available for LLVM14 and above)"))); bool isUsingLegacyPassManager() { return passmanager == 0; } // Math options bool fFastMath; // Storage for the dynamically created ffast-math option. llvm::FastMathFlags defaultFMF; void setDefaultMathOptions(llvm::TargetOptions &targetOptions) { if (fFastMath) { defaultFMF.setFast(); targetOptions.UnsafeFPMath = true; } } cl::opt fNoDiscardValueNames("fno-discard-value-names", cl::ZeroOrMore, cl::desc("Do not discard value names in LLVM IR")); cl::opt fNullPointerIsValid( "fno-delete-null-pointer-checks", cl::ZeroOrMore, cl::desc( "Treat null pointer dereference as defined behavior when optimizing " "(instead of _un_defined behavior). This prevents the optimizer from " "assuming that any dereferenced pointer must not have been null and " "optimize away the branches accordingly.")); cl::opt fNoExceptions("fno-exceptions", cl::ZeroOrMore, cl::desc("Disable generation of exception stack unwinding " "code, assuming no Exceptions will be thrown")); cl::opt fNoModuleInfo("fno-moduleinfo", cl::ZeroOrMore, cl::desc("Disable generation of ModuleInfos")); cl::opt fNoRTTI("fno-rtti", cl::ZeroOrMore, cl::desc("Disable generation of TypeInfos")); cl::opt fSplitStack("fsplit-stack", cl::ZeroOrMore, cl::desc("Use segmented stack (see Clang documentation)")); cl::opt allinst("allinst", cl::ZeroOrMore, cl::location(global.params.allInst), cl::desc("Generate code for all template instantiations")); cl::opt nestedTemplateDepth( "template-depth", cl::ZeroOrMore, cl::location(global.recursionLimit), cl::init(500), cl::desc("Set maximum number of nested template instantiations")); // legacy options superseded by `-preview=dip` cl::opt useDIP25("dip25", cl::ZeroOrMore, cl::ReallyHidden, cl::desc("Implement DIP25 (sealed references)")); cl::opt useDIP1000("dip1000", cl::ZeroOrMore, cl::ReallyHidden, cl::desc("Implement DIP1000 (scoped pointers)")); static cl::opt useDIP1008("dip1008", cl::ZeroOrMore, cl::location(global.params.ehnogc), cl::desc("Implement DIP1008 (@nogc Throwable)"), cl::ReallyHidden); cl::opt betterC( "betterC", cl::ZeroOrMore, cl::location(global.params.betterC), cl::desc("Omit generating some runtime information and helper functions")); // `-cov[=|ctfe]` parser. struct CoverageParser : public cl::parser { explicit CoverageParser(cl::Option &O) : cl::parser(O) {} bool parse(cl::Option &O, llvm::StringRef /*ArgName*/, llvm::StringRef Arg, DummyDataType & /*Val*/) { global.params.cov = true; if (Arg.empty()) { return false; } if (Arg == "ctfe") { global.params.ctfe_cov = true; return false; } unsigned char percent = 0; if (Arg.getAsInteger(0, percent)) { return O.error("'" + Arg + "' value invalid for required coverage percentage"); } if (percent > 100) { return O.error("required coverage percentage must be <= 100"); } global.params.covPercent = percent; return false; } }; static cl::opt coverageAnalysis( "cov", cl::ZeroOrMore, cl::ValueOptional, cl::desc("Compile-in code coverage analysis and .lst file generation\n" "Use -cov= for n% minimum required coverage\n" "Use -cov=ctfe to include code executed during CTFE")); cl::opt coverageIncrement( "cov-increment", cl::ZeroOrMore, cl::desc("Set the type of coverage line count increment instruction"), cl::init(CoverageIncrement::_default), cl::values(clEnumValN(CoverageIncrement::_default, "default", "Use the default (atomic)"), clEnumValN(CoverageIncrement::atomic, "atomic", "Atomic increment"), clEnumValN(CoverageIncrement::nonatomic, "non-atomic", "Non-atomic increment (not thread safe)"), clEnumValN(CoverageIncrement::boolean, "boolean", "Don't read, just set counter to 1"))); // Compilation time tracing options cl::opt fTimeTrace( "ftime-trace", cl::ZeroOrMore, cl::desc("Turn on time profiler. Generates JSON file " "based on the output filename (also see --ftime-trace-file).")); cl::opt fTimeTraceGranularity( "ftime-trace-granularity", cl::ZeroOrMore, cl::init(500), cl::desc( "Minimum time granularity (in microseconds) traced by time profiler")); cl::opt fTimeTraceFile("ftime-trace-file", cl::desc("Specify time trace file destination"), cl::value_desc("filename")); cl::opt ltoMode( "flto", cl::ZeroOrMore, cl::desc("Set LTO mode, requires linker support"), cl::init(LTO_None), cl::values( clEnumValN(LTO_Full, "full", "Merges all input into a single module"), clEnumValN(LTO_Thin, "thin", "Parallel importing and codegen (faster than 'full')"))); cl::opt saveOptimizationRecord("fsave-optimization-record", cl::value_desc("filename"), cl::desc("Generate a YAML optimization record file " "of optimizations performed by LLVM"), cl::ValueOptional); #if LDC_LLVM_VER >= 1300 // LLVM < 13 has "--warn-stack-size", but let's not do the effort of forwarding // the string to that option, and instead let the user do it himself. cl::opt fWarnStackSize("fwarn-stack-size", cl::ZeroOrMore, cl::init(UINT_MAX), cl::desc("Warn for stack size bigger than the given number"), cl::value_desc("threshold")); #endif #if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX cl::list dcomputeTargets("mdcompute-targets", cl::CommaSeparated, cl::desc("Generates code for the specified DCompute target" " list. Use 'ocl-xy0' for OpenCL x.y, and " "'cuda-xy0' for CUDA CC x.y"), cl::value_desc("targets")); cl::opt dcomputeFilePrefix("mdcompute-file-prefix", cl::desc("Prefix to prepend to the generated kernel files."), cl::init("kernels"), cl::value_desc("prefix")); #endif #if defined(LDC_DYNAMIC_COMPILE) cl::opt enableDynamicCompile( "enable-dynamic-compile", cl::desc("Enable dynamic compilation"), cl::init(false)); cl::opt dynamicCompileTlsWorkaround( "dynamic-compile-tls-workaround", cl::desc("Enable dynamic compilation TLS workaround"), cl::init(true), cl::Hidden); #endif #if LDC_LLVM_VER >= 1700 bool enableOpaqueIRPointers = true; // typed pointers are no longer supported from LLVM 17 #elif LDC_LLVM_VER >= 1400 bool enableOpaqueIRPointers = false; #endif static cl::extrahelp footer("\n" "-d-debug can also be specified without options, in which case it " "enables all debug checks (i.e. asserts, boundschecks, contracts " "and invariants) as well as acting as -d-debug=1.\n\n" "Boolean options can take an optional value, e.g., " "-link-defaultlib-shared=.\n" "Boolean options marked with (*) also have a -disable-FOO variant " "with inverted meaning.\n"); /// Create commandline options that may clash with LLVM's options (depending on /// LLVM version and on LLVM configuration), and that thus cannot be created /// using static construction. /// The clashing LLVM options are suffixed with "llvm-" and hidden from the /// -help output. void createClashingOptions() { llvm::StringMap &map = cl::getRegisteredOptions(); auto renameAndHide = [&map](const char *from, const char *to) { auto i = map.find(from); if (i != map.end()) { cl::Option *opt = i->getValue(); map.erase(i); if (to) { opt->setArgStr(to); opt->setHiddenFlag(cl::Hidden); map[to] = opt; } } }; // Step 1. Hide the clashing LLVM options. // LLVM 3.7 introduces compiling as shared library. The result // is a clash in the command line options. renameAndHide("color", "llvm-color"); renameAndHide("ffast-math", "llvm-ffast-math"); renameAndHide("float-abi", "llvm-float-abi"); // Step 2. Add the LDC options. new cl::opt>( "color", cl::ZeroOrMore, cl::location(global.params.v.color), cl::desc("(*) Force colored console output")); new cl::opt("ffast-math", cl::ZeroOrMore, cl::location(fFastMath), cl::desc("Set @fastmath for all functions.")); new cl::opt( "float-abi", cl::desc("ABI/operations to use for floating-point types:"), cl::ZeroOrMore, cl::location(floatABI), cl::init(FloatABI::Default), cl::values( clEnumValN(FloatABI::Default, "default", "Target default floating-point ABI"), clEnumValN(FloatABI::Soft, "soft", "Software floating-point ABI and operations"), clEnumValN( FloatABI::SoftFP, "softfp", "Soft-float ABI, but hardware floating-point instructions"), clEnumValN(FloatABI::Hard, "hard", "Hardware floating-point ABI and instructions"))); #if LDC_LLVM_VER >= 1400 renameAndHide("opaque-pointers", nullptr); // remove new cl::opt( "opaque-pointers", cl::ZeroOrMore, cl::location(enableOpaqueIRPointers), cl::desc("Use opaque IR pointers (experimental!)"), cl::Hidden); #endif } /// Hides command line options exposed from within LLVM that are unlikely /// to be useful for end users from the -help output. void hideLLVMOptions() { static const char *const hiddenOptions[] = { "aarch64-neon-syntax", "aarch64-use-aa", "abort-on-max-devirt-iterations-reached", "addrsig", "align-loops", "allow-ginsert-as-artifact", "amdgpu-bypass-slow-div", "amdgpu-disable-loop-alignment", "amdgpu-disable-power-sched", "amdgpu-dpp-combine", "amdgpu-dump-hsa-metadata", "amdgpu-enable-flat-scratch", "amdgpu-enable-global-sgpr-addr", "amdgpu-enable-merge-m0", "amdgpu-enable-power-sched", "amdgpu-igrouplp", "amdgpu-promote-alloca-to-vector-limit", "amdgpu-reserve-vgpr-for-sgpr-spill", "amdgpu-sdwa-peephole", "amdgpu-use-aa-in-codegen", "amdgpu-verify-hsa-metadata", "amdgpu-vgpr-index-mode", "arm-add-build-attributes", "arm-implicit-it", "asm-instrumentation", "asm-show-inst", "atomic-counter-update-promoted", "atomic-first-counter", "basic-block-sections", "basicblock-sections", "bounds-checking-single-trap", "cfg-hide-cold-paths", "cfg-hide-deoptimize-paths", "cfg-hide-unreachable-paths", "code-model", "cost-kind", "cppfname", "cppfor", "cppgen", "cvp-dont-add-nowrap-flags", "cvp-dont-process-adds", "debug-counter", "debug-entry-values", "debugger-tune", "debugify-func-limit", "debugify-level", "debugify-quiet", "debug-info-correlate", "denormal-fp-math", "denormal-fp-math-f32", "disable-debug-info-verifier", "disable-i2p-p2i-opt", "disable-objc-arc-checkforcfghazards", "disable-promote-alloca-to-lds", "disable-promote-alloca-to-vector", "disable-slp-vectorization", "disable-spill-fusing", "do-counter-promotion", "dot-cfg-mssa", "dwarf64", "emit-call-site-info", "emit-dwarf-unwind", "emscripten-cxx-exceptions-allowed", "emscripten-cxx-exceptions-whitelist", "emulated-tls", "enable-approx-func-fp-math", "enable-correct-eh-support", "enable-cse-in-irtranslator", "enable-cse-in-legalizer", "enable-emscripten-cxx-exceptions", "enable-emscripten-sjlj", "enable-fp-mad", "enable-gvn-hoist", "enable-gvn-memdep", "enable-gvn-sink", "enable-implicit-null-checks", "enable-jmc-instrument", "enable-load-in-loop-pre", "enable-load-pre", "enable-loop-simplifycfg-term-folding", "enable-misched", "enable-name-compression", "enable-no-infs-fp-math", "enable-no-nans-fp-math", "enable-no-signed-zeros-fp-math", "enable-no-trapping-fp-math", "enable-objc-arc-annotations", "enable-objc-arc-opts", "enable-pie", "enable-scoped-noalias", "enable-split-backedge-in-load-pre", "enable-tbaa", "enable-unsafe-fp-math", "exception-model", "exhaustive-register-search", "expensive-combines", "experimental-debug-variable-locations", "fatal-assembler-warnings", "filter-print-funcs", "force-dwarf-frame-section", "force-opaque-pointers", "fs-profile-debug-bw-threshold", "fs-profile-debug-prob-diff-threshold", "generate-merged-base-profiles", "gpsize", "hash-based-counter-split", "hot-cold-split", "ignore-xcoff-visibility", "imp-null-check-page-size", "imp-null-max-insts-to-consider", "import-all-index", "incremental-linker-compatible", "instcombine-code-sinking", "instcombine-guard-widening-window", "instcombine-max-iterations", "instcombine-max-num-phis", "instcombine-max-sink-users", "instcombine-maxarray-size", "instcombine-negator-enabled", "instcombine-negator-max-depth", "instcombine-unsafe-select-transform", "instrprof-atomic-counter-update-all", "internalize-public-api-file", "internalize-public-api-list", "iterative-counter-promotion", "join-liveintervals", "jump-table-type", "limit-float-precision", "lower-global-dtors-via-cxa-atexit", "lto-embed-bitcode", "matrix-default-layout", "matrix-print-after-transpose-opt", "matrix-propagate-shape", "max-counter-promotions", "max-counter-promotions-per-loop", "mc-relax-all", "mc-x86-disable-arith-relaxation", "mcabac", "meabi", "memop-size-large", "memop-size-range", "merror-missing-parenthesis", "merror-noncontigious-register", "mfuture-regs", "mhvx", "mips-compact-branches", "mips16-constant-islands", "mips16-hard-float", "mir-strip-debugify-only", "misexpect-tolerance", "mlsm", "mno-compound", "mno-fixup", "mno-ldc1-sdc1", "mno-pairing", "mwarn-missing-parenthesis", "mwarn-noncontigious-register", "mwarn-sign-mismatch", "no-discriminators", "no-type-check", "no-xray-index", "nozero-initialized-in-bss", "nvptx-sched4reg", "objc-arc-annotation-target-identifier", "opaque-pointers", "pie-copy-relocations", "poison-checking-function-local", "polly-dump-after", "polly-dump-after-file", "polly-dump-before", "polly-dump-before-file", "pre-RA-sched", "print-after-all", "print-before-all", "print-machineinstrs", "print-module-scope", "print-pipeline-passes", "profile-estimator-loop-weight", "profile-estimator-loop-weight", "profile-file", "profile-info-file", "profile-verifier-noassert", "pseudo-probe-for-profiling", "r600-ir-structurize", "rdf-dump", "rdf-limit", "recip", "regalloc", "relax-elf-relocations", "remarks-section", "rewrite-map-file", "rng-seed", "runtime-counter-relocation", "safepoint-ir-verifier-print-only", "sample-profile-check-record-coverage", "sample-profile-check-sample-coverage", "sample-profile-inline-hot-threshold", "sample-profile-max-propagate-iterations", "shrink-wrap", "simplify-mir", "skip-ret-exit-block", "speculative-counter-promotion-max-exiting", "speculative-counter-promotion-to-loop", "spiller", "spirv-debug", "spirv-erase-cl-md", "spirv-lower-const-expr", "spirv-mem2reg", "spirv-no-deref-attr", "spirv-text", "spirv-verify-regularize-passes", "split-machine-functions", "spv-dump-deps", "spv-lower-saddwithoverflow-validate", "spvbool-validate", "spvmemmove-validate", "stack-alignment", "stack-protector-guard", "stack-protector-guard-offset", "stack-protector-guard-reg", "stack-size-section", "stack-symbol-ordering", "stackmap-version", "static-func-full-module-prefix", "static-func-strip-dirname-prefix", "stats", "stats-json", "strict-dwarf", "strip-debug", "struct-path-tbaa", "summary-file", "sve-tail-folding", "swift-async-fp", "tail-predication", "tailcallopt", "thinlto-assume-merged", "thread-model", "time-passes", "time-trace-granularity", "tls-size", "type-based-intrinsic-cost", "unfold-element-atomic-memcpy-max-elements", "unique-basic-block-section-names", "unique-bb-section-names", "unique-section-names", "unit-at-a-time", "use-ctors", "vec-extabi", "verify-debug-info", "verify-dom-info", "verify-legalizer-debug-locs", "verify-loop-info", "verify-loop-lcssa", "verify-machine-dom-info", "verify-regalloc", "verify-region-info", "verify-scev", "verify-scev-maps", "vp-counters-per-site", "vp-static-alloc", "wasm-enable-eh", "wasm-enable-sjlj", "x86-align-branch", "x86-align-branch-boundary", "x86-branches-within-32B-boundaries", "x86-early-ifcvt", "x86-pad-max-prefix-size", "x86-recip-refinement-steps", "x86-use-vzeroupper", "xcoff-traceback-table", // We enable -fdata-sections/-ffunction-sections by default where it makes // sense for reducing code size, so hide them to avoid confusion. // // We need our own switch as these two are defined by LLVM and linked to // static TargetMachine members, but the default we want to use depends // on the target triple (and thus we do not know it until after the // command line has been parsed). "fdata-sections", "ffunction-sections", "data-sections", "function-sections"}; // pulled in from shared LLVM headers, but unused or not desired in LDC static const char *const removedOptions[] = {"disable-tail-calls", "fatal-warnings", "filetype", "no-deprecated-warn", "no-warn", "stackrealign", "start-after", "stop-after", "trap-func", "W"}; llvm::StringMap &map = cl::getRegisteredOptions(); for (const auto name : hiddenOptions) { // Check if option exists first for resilience against LLVM changes // between versions. auto it = map.find(name); if (it != map.end()) { it->second->setHiddenFlag(cl::Hidden); } } for (const auto name : removedOptions) { auto it = map.find(name); if (it != map.end()) { map.erase(it); } } } } // namespace opts