337 řádky
11 KiB
C++
337 řádky
11 KiB
C++
/* Copyright (c) 2009 - 2021 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 <string>
|
|
#include <vector>
|
|
#include <cstdio>
|
|
#include "top.hpp"
|
|
#include "library.hpp"
|
|
#include <cassert>
|
|
#include <sstream>
|
|
#ifdef __linux__
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef _WIN32
|
|
#include <process.h>
|
|
#include <cstdio>
|
|
#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_<sth> : Only one in each group is required.
|
|
OA_<sth> : Each one is independent, all OA_<sth> 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<flag>, machine-independent
|
|
OFA_PREFIX_M = 0x200, // -m<flag>, machine-dependent
|
|
OFA_PREFIX_W = 0x300, // -W<flag>, 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 |
|
|
// handling DUMP_BC_ORIGINAL would require a fair amount of work,
|
|
// since the output of comgr is already optimized
|
|
DUMP_BC_OPTIMIZED | DUMP_BC_LINKED | 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<std::string> clangOptions; // options passed into Clang frontend
|
|
std::string llvmOptions; // options passed into backend (llvm)
|
|
std::vector<std::string> 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];
|
|
return 1 & ((*p) >> c);
|
|
}
|
|
|
|
bool isOptionSeen(int option_ndx) const { return (getFlag(option_ndx) == FLAG_SEEN); }
|
|
|
|
int getLLVMArgc() const { 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() const { 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.
|
|
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<char*> MemoryHandles;
|
|
|
|
bool UseDefaultWGS;
|
|
|
|
bool dumpEncrypt(DumpFlags f) const {
|
|
return ((encryptCode == 0) || // return true if not encrypted
|
|
(f & DUMP_ENCRYPT));
|
|
}
|
|
|
|
std::string getStringFromStringVec(std::vector<std::string>& 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);
|
|
inline bool parseLinkOptions(std::string& options, Options& Opts) {
|
|
return parseAllOptions(options, Opts, true /*linkOptsOnly*/);
|
|
}
|
|
|
|
|
|
} // namespace option
|
|
|
|
} // namespace amd
|
|
|
|
#endif // _UTILS_OPTIONS_HPP_
|