// // Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved. // #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_