/* Copyright (c) 2009-present Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UTILS_OPTIONS_HPP_ #define _UTILS_OPTIONS_HPP_ #include #include #include #include "top.hpp" #include "library.hpp" #include #include #ifdef __linux__ #include #endif #ifdef _WIN32 #include #include #endif namespace amd { class Device; namespace option { // Option Type : Info[0:5] enum OptionType { OT_BOOL, OT_INT32, OT_UINT32, OT_CSTRING, OT_UCHAR, OT_MASK = 0x3f }; /* Option's Attributes : Info[6:31] OxA_ : Only one in each group is required. OA_ : Each one is independent, all OA_ can be OR'ed together. */ // Option Value Attributes enum OptionValue { OVA_OPTIONAL = 0x00, // value is optional OVA_REQUIRED = 0x40, // value is required to appear; OVA_DISALLOWED = 0x80, // value may not be specified. OVA_MASK = 0xC0 }; // Option Form Attributes enum OptionForm { OFA_NORMAL = 0x000, // normal form, no prefix OFA_PREFIX_F = 0x100, // -f, machine-independent OFA_PREFIX_M = 0x200, // -m, machine-dependent OFA_PREFIX_W = 0x300, // -W, warning (TODO) OFA_MASK = 0x300 }; // Option Group, at least one must be used. enum OptionGroup { OA_RUNTIME = 0x400, OA_CLC = 0x800, OA_LINK_EXE = 0x1000, OA_LINK_LIB = 0x2000 }; // Option Value Separator, at least one must be used. enum OptionValueSeparator { OA_SEPARATOR_NONE = 0x4000, OA_SEPARATOR_EQUAL = 0x8000, OA_SEPARATOR_SPACE = 0x10000 }; // Option visibility : at least one must be used. enum OptionVisibility { OVIS_PUBLIC = 0x00000, // ducumented OVIS_SUPPORT = 0x20000, // supported, but undocumented OVIS_INTERNAL = 0x40000, // internal-only, not available in product release OVIS_MASK = 0x60000 }; // Option other attributes : optional enum OptionMisc { OA_MISC_ALIAS = 0x80000 // An alias option is one that refers to another option or options // and its meaning is hard-coded in setAliasOptionVariable(). }; typedef bool OT_BOOL_t; typedef int32_t OT_INT32_t; typedef uint32_t OT_UINT32_t; typedef const char* OT_CSTRING_t; typedef unsigned char OT_UCHAR_t; // This must be a POD struct OptionDescriptor { const char* NameShort; // short option starts with - const char* NameLong; // long option starts with -- uint32_t Info; // defined by above enums uint32_t OptionOffset; // member offset to OptionVariable int64_t DefaultVal; // default value for option of non-string type int64_t ValMin; // (ValMin, ValMax) is the option's Value range int64_t ValMax; // for option of non-string type const char* DefaultString; // default value for string. const char* Description; // Short Description for this option. -h will show this. }; #define OPTION_sname(o) ((o)->NameShort) #define OPTION_lname(o) ((o)->NameLong) #define OPTION_type(o) ((o)->Info & OT_MASK) #define OPTION_value(o) ((o)->Info & OVA_MASK) #define OPTION_form(o) ((o)->Info & OFA_MASK) #define OPTION_vis(o) ((o)->Info & OVIS_MASK) #define OPTION_info(o) ((o)->Info) #define OPTION_offset(o) ((o)->OptionOffset) #define OPTION_default(o) ((o)->DefaultVal) #define OPTION_min(o) ((o)->ValMin) #define OPTION_max(o) ((o)->ValMax) #define OPTION_defaultstr(o) ((o)->DefaultString) #define OPTION_desc(o) ((o)->Description) // OptionVariables must be a POD struct OptionVariables { #define OPTION(type, a, sn, ln, var, ideft, imin, imax, sdeft, desc) type##_t var ; #define NOPTION(type, a, sn, ln, var, ideft, imin, imax, sdeft, desc) #define FLAG(type, a, sn, var, deft, desc) type##_t var ; #include "OPTIONS.def" #undef OPTION #undef NOPTION #undef FLAG }; #define OPTION_valueSeparator(c) (((c) == ' ') || ((c) == '=')) #define OFFSET(var) ((uint32_t)&(((OptionVariable *)0)->var)) enum OptionIdentifier { #define OPTION(type, a, sn, ln, var, ideft, imin, imax, sdeft, desc) OID_##var , #define NOPTION(type, a, sn, ln, var, ideft, imin, imax, sdeft, desc) OID_##var , #define FLAG(type, a, sn, var, deft, desc) OID_##var, #include "OPTIONS.def" OID_LAST #undef OPTION #undef NOPTION #undef FLAG }; // Only option that is a RUNTIME option and is not an alias option has an entry in OptionVariables #define OPTIONHasOVariable(od) \ ((OPTION_info(od) & (OA_RUNTIME | OA_MISC_ALIAS)) == OA_RUNTIME) // DumpFlags defines the values for oVariables->DumpFlags enum DumpFlags { DUMP_NONE = 0x00000000, // default DUMP_CL = 0x00000001, // CL source DUMP_I = 0x00000002, // pre-processed CL source DUMP_S = 0x00000004, // x86 assembly text DUMP_O = 0x00000008, // x86 object / GPU code object DUMP_DLL = 0x00000010, // x86 DLL (.so) DUMP_IL = 0x00000020, // per-kernel IL (GPU) DUMP_ISA = 0x00000040, // per-kernel assembly text (GPU) DUMP_BIF = 0x00000080, // binary for all kernels (GPU) DUMP_BC_ORIGINAL = 0x00000100, // input bitcode (generated by clc) DUMP_BC_LINKED = 0x00000200, // bitcode after linking and before optimization DUMP_BC_OPTIMIZED = 0x00000400, // bitcode after optimization (llvm opt's output) DUMP_CGIL = 0x00000800, // output il generated by Codegen (llvm llc's output) DUMP_DEBUGIL = 0x00001000, // debug il (from MDParser, dwarf refers to) DUMP_SPIRV = 0x00002000, // SPIR-V binary DUMP_BC_SPIRV = 0x00004000, // bitcode translated from SPIR-V // For a binary is encrypted, can only dump the following DUMP_ENCRYPT = (DUMP_DLL | DUMP_BIF), // For a release product, can only dump the following DUMP_PRODUCT_FLAGS = (DUMP_CL | DUMP_I | DUMP_S | DUMP_O | DUMP_DLL | DUMP_IL |DUMP_CGIL | DUMP_DEBUGIL | DUMP_ISA | DUMP_BIF), DUMP_ALL = 0x00007FFF // Everything }; enum OptLevelFlags : unsigned char { OPT_O0 = '0', // No optimization setting. OPT_O1 = '1', OPT_O2 = '2', OPT_O3 = '3', OPT_O4 = '4', OPT_O5 = '5', OPT_OG = 'g', // g ASCII OPT_OS = 's', // s ASCII OPT_Error = 0, // Invalid optimization set /** Canary Value that guards against enum changes * @warning This value cannot be changed without updating the appropriate * tests and should NEVER be decreased. */ optLast = 117 }; class Options { public: std::string origOptionStr; OptionVariables *oVariables; // pointer to a struct of all option variables std::string clcOptions; // options passed into EDG frontend (clc) std::vector clangOptions; // options passed into Clang frontend std::string llvmOptions; // options passed into backend (llvm) std::vector finalizerOptions; // options passed into finalizer // Given as build option int WorkGroupSize[3]; // -1: use default int NumAvailGPRs; unsigned kernelArgAlign; Options (); ~Options (); bool isDumpFlagSet(DumpFlags f) { return ((oVariables->DumpFlags) & f) && dumpEncrypt(f); } // Definition of each entry in flags // Note: this is 1-bit entry now, it may need to be expanded to // more than 1 bit later. enum { FLAG_UNSEEN = 0, FLAG_SEEN = 1 }; void setFlag(int option_ndx, uint32_t v) { int r = option_ndx/32; int c = option_ndx%32; uint32_t *p = &flags[r]; uint32_t b = (1 << c); v = (v << c); *p = ((*p) & (~b)) | v; } uint32_t getFlag(int option_ndx) const { int r = option_ndx/32; int c = option_ndx%32; const uint32_t *p = &flags[r]; uint32_t b = (1 << c); return 1 & ((*p) >> c); } bool isOptionSeen(int option_ndx) const { return (getFlag(option_ndx) == FLAG_SEEN); } int getLLVMArgc() { return llvmargc; } char** getLLVMArgv() { return llvmargv; } void setLLVMArgs (int argc, char** argv) { llvmargc = argc; llvmargv = argv; } void recordMemoryHandle(char* handle) { MemoryHandles.push_back(handle); } // Do post-parse processing After parsing all options, void postParseInit(); void setBuildNo(unsigned int bnum) { buildNo = bnum; } unsigned int getBuildNo() const { return buildNo; } void setCurrKernelName(const char* name) { currKernelName = name; } const char* getCurrKernelName() const { return currKernelName; } std::string getDumpFileName(const std::string& ext); void setPerBuildInfo(const char* val, int encrypt, bool device); bool isCStrOptionsEqual(const char *cs1, const char* cs2) const; bool useDefaultWGS() { return UseDefaultWGS; } void setDefaultWGS(bool V) { UseDefaultWGS = V; } std::string& optionsLog() { return OptionsLog; } // Returns whether this set of options equals to another set of options bool equals(const Options& other, bool ignoreClcOptions=false) const; // Set the option variables same as defined in "other" bool setOptionVariablesAs(const Options& other); std::string getFinalizerOptions() { return getStringFromStringVec(finalizerOptions); } private: std::string fullPath, baseName; long basename_max; std::string OptionsLog; // One bit for each flag. const int flagsSize; uint32_t flags[(OID_LAST + 31)/32]; int llvmargc; char** llvmargv; // buildNo is a unique number for each device build, save it here so that // dumping can use it in its file names. // // Note that buildNo, dumpFileRoot, and encryptCode are valid only during the lifetime // of a device build. unsigned int buildNo; std::string dumpFileRoot; const char* currKernelName; int encryptCode; std::vector MemoryHandles; bool UseDefaultWGS; bool dumpEncrypt(DumpFlags f) { return ((encryptCode == 0) || // return true if not encrypted (f & DUMP_ENCRYPT)); } std::string getStringFromStringVec(std::vector& stringVec); void setDumpFileName(const char* val); public: LibrarySelector libraryType_; std::string sourceFileName_; }; OptionDescriptor* getOptDescTable(); bool init(); bool teardown(); bool parseAllOptions(std::string& options, Options& Opts, bool linkOptsOnly, bool isLC); inline bool parseLinkOptions(std::string& options, Options& Opts, bool isLC) { return parseAllOptions(options, Opts, true/*linkOptsOnly*/, isLC); } } // option } // amd #endif // _UTILS_OPTIONS_HPP_