Files
rocm-systems/projects/clr/rocclr/compiler/lib/utils/options.cpp
T
2025-10-23 11:21:49 -07:00

1559 строки
49 KiB
C++

/* Copyright (c) 2008 - 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. */
#include <string>
#include <map>
#include <numeric>
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <iterator>
#include <cassert>
#include <regex>
#include "options.hpp"
namespace {
using namespace amd::option;
#define SKIP_INTERNAL_OPTION 1
/*
Macro OPTION and NOPTION are general option macros. And FLAG is a
special, simple macro with the form -<flag>=<val>. The FLAG is similar
to a flag defined in flags.hpp, so that it is easier for people who are
familiar with flags.hpp to use FLAG.
*/
#define OPTION(type, a, sn, ln, var, ideft, imin, imax, sdeft, desc) \
{sn, \
ln, \
(type) | (a), \
(uint32_t)reinterpret_cast<size_t>(&(((OptionVariables*)0)->var)), \
(int64_t)ideft, \
imin, \
imax, \
sdeft, \
desc},
#define NOPTION(type, a, sn, ln, var, ideft, imin, imax, sdeft, desc) \
{sn, ln, (type) | (a), 0, (int64_t)ideft, imin, imax, sdeft, desc},
/*
FLAG is a special option with the form
-<flag>=<val>
*/
#define FLAG(type, a, sn, var, deft, desc) \
{sn, \
NULL, \
(type) | (a) | OA_RUNTIME | OVA_REQUIRED | OA_SEPARATOR_EQUAL, \
(uint32_t)reinterpret_cast<size_t>(&(((OptionVariables*)0)->var)), \
(type == OT_CSTRING) ? (int64_t)0 : (int64_t)deft, \
(type == OT_INT32) ? -0x80000000LL : 0LL, \
(type == OT_INT32) ? 0x7FFFFFFFLL : ((type == OT_UINT32) ? 0xFFFFFFFFLL : 0LL), \
(type == OT_CSTRING) ? (const char*)deft : NULL, \
desc},
OptionDescriptor OptDescTable[] = {
#include "OPTIONS.def"
{0, 0, 0, 0, 0, 0, 0, 0, 0} // dummy entry
};
#undef OPTION
#undef NOPTION
#undef FLAG
#define OPTION_var(ix, ovars) (reinterpret_cast<char*>(ovars) + OPTION_offset(OptDescTable + ix))
/*
[0] : map from option's short name to OptDescTable's index
[1] : map from option's long name to OptDescTable's index
Any prefix option (-f/-fno, -m/-mno) has no long name, and must have
a value separator if it requires a value.
*/
std::map<std::string, int> OptionNameMap[2] ROCCLR_INIT_PRIORITY(101);
std::map<std::string, int> NoneSeparatorOptionMap[2] ROCCLR_INIT_PRIORITY(101);
// prefix -f/-fno- options
std::map<std::string, int> FOptionMap ROCCLR_INIT_PRIORITY(101);
// prefix -m/-mno- options
std::map<std::string, int> MOptionMap ROCCLR_INIT_PRIORITY(101);
bool setOptionVariable(OptionDescriptor* oDesc, OptionVariables* oVars, int64_t IValue,
const char* SValue);
/*
Note: When adding any option that has OVA_OPTIONAL as its value attribute,
make sure that the code for returning the second default is added
int this function!!!
getDefault2() : get the second default value for an option given as
'OptDescTableIx'.
The second default is a default VALUE if an option is PRESENT in the option string
but its value is NOT GIVEN (its attribute must be OVA_OPTIONAL). This is different
from the (first) default that is registerred in OptionDescriptor, and the first
default gives the default value when an option is NOT PRESENT in the option string.
For instance,
-O[0-3] : optimization level
first default : 3
This means if there is no -O[0-3] present in the option string, the default
is 3.
second default : 3
This means if -O is present but no level is given, the level is 3 (second
default).
In this case, the first default and the second default is the same, but in general
they may be different. Take -O in gcc, the first default is 0, the second default
is 2.
We don't expect many options to have attributes OVA_OPTIONAL, therefore, the second
default is set here in code instead of registerring it in OptionDescriptor. When
adding an option that needs the second default, make sure this function return
the second default.
*/
void getDefault2(int OptDescTableIx, int64_t& idefault2, const char*& sdefault2) {
switch (OptDescTableIx) {
case OID_ShowHelp:
sdefault2 = "public";
break;
case OID_SaveTemps:
case OID_SaveTempsAll:
sdefault2 = NULL;
break;
case OID_OptLevel:
idefault2 = amd::option::OPT_O3;
break;
case OID_OptUseNative:
sdefault2 = "all";
break;
default:
assert(false && "The second default value is not given");
break;
}
}
bool setAliasOptionVariable(int OptDescTableIx, Options& Opts, int64_t IValue, const char* SValue) {
OptionDescriptor* od;
OptionVariables* oVars = Opts.oVariables;
switch (OptDescTableIx) {
case OID_OptDisable:
//
// -cl-opt-disable is equivalent to -O0.
//
Opts.setFlag(OID_OptLevel, 1);
od = &OptDescTable[OID_OptLevel];
assert((IValue > 0) && "Internal Error: -cl-opt-disable is present, but with wrong value");
if (!setOptionVariable(od, oVars, (int64_t)amd::option::OPT_O0, NULL)) {
return false;
}
return true;
case OID_GPU32BitIsa:
// -m32 == "no -m64", ie, 64-bit code generation off.
Opts.setFlag(OID_GPU64BitIsa, 1);
od = &OptDescTable[OID_GPU64BitIsa];
assert((IValue > 0) && "Internal Error: -m32 is present, but with wrong value");
if (!setOptionVariable(od, oVars, (int64_t)0, NULL)) {
return false;
}
return true;
case OID_SaveTemps:
case OID_SaveTempsAll:
case OID_Output:
uint32_t flags;
if (OptDescTableIx == OID_SaveTemps) {
// Dump .cl, .i(.ii), .amdil, .isa, .s, dll, calimage
flags = DUMP_CL | DUMP_I | DUMP_S | DUMP_O | DUMP_DLL | DUMP_CGIL | DUMP_DEBUGIL | DUMP_IL |
DUMP_ISA;
} else if (OptDescTableIx == OID_SaveTempsAll) {
flags = DUMP_ALL;
} else { // OID_Output
flags = DUMP_BIF;
if (SValue == NULL) {
assert(false && "Missing value for option -o <prefix>");
return false;
}
}
// Make sure flags is or'ed with the previous ones.
if (Opts.isOptionSeen(OID_DumpFlags)) {
flags |= oVars->DumpFlags;
}
Opts.setFlag(OID_DumpFlags, 1);
od = &OptDescTable[OID_DumpFlags];
if (!setOptionVariable(od, oVars, (int64_t)flags, NULL)) {
return false;
}
if (SValue != NULL) {
// Reset DumpPrefix
Opts.setFlag(OID_DumpPrefix, 1);
od = &OptDescTable[OID_DumpPrefix];
if (!setOptionVariable(od, oVars, (int64_t)0, SValue)) {
return false;
}
}
return true;
default:
break;
}
return true;
}
void ShowOptionsHelp(const char* helpValue, Options& Opts) {
// -h[--help][=public|all] : public is the second default
bool showAll = false;
bool showSupport = false;
/* If SKIP_INTERNAL_OPTION is set, only use public options */
#ifndef SKIP_INTERNAL_OPTION
if (::strcmp(helpValue, "all") == 0) {
showAll = true;
} else if (::strcmp(helpValue, "support") == 0) {
showSupport = true;
}
#endif
Opts.optionsLog() =
"Option Summary:\n"
"\tUse those options in clBuildProgram() directly in the OpenCL host application or\n"
"\tduring runtime by setting environment variables : AMD_OCL_BUILD_OPTIONS and \n"
"\tAMD_OCL_BUILD_OPTIONS_APPEND. AMD_OCL_BUILD_OPTIONS will override the options\n"
"\tused in the host application, whereas AMD_OCL_BUILD_OPTIONS_APPEND appends to\n"
"\tthe options. For example, assume '-cl-opt-disable' is used in the host application,\n"
"\tand with\n"
"\t\tset AMD_OCL_BUILD_OPTIONS=-O\n"
"\tit will override '-cl-opt-disable' with '-O'; with\n"
"\t\tset AMD_OCL_BUILD_OPTIONS_APPEND=-g\n"
"\tit will append '-g' to '-cl-opt-disable' (ie '-cl-opt-disable -g').\n\n"
"\tThose environment variables are useful for changing build options without changing\n"
"\tand re-building (compiling) the host application.\n\n"
"OPTIONS:\n";
for (int i = 0; i < OID_LAST; ++i) {
OptionDescriptor* od = &OptDescTable[i];
if ((OPTION_vis(od) != OVIS_PUBLIC) && !showAll &&
!(showSupport && (OPTION_vis(od) != OVIS_INTERNAL))) {
continue;
}
// Print Value -- value to be shown in the help message
std::string pntVal;
switch (OPTION_type(od)) {
case OT_CSTRING:
if ((i == OID_WFComma) || (i == OID_WBComma) || (i == OID_WHComma)) {
pntVal = "<options>";
} else if (i == OID_SaveTemps) {
pntVal = "<prefix>";
} else {
pntVal = "<value>";
}
break;
case OT_BOOL:
pntVal = "0|1";
break;
case OT_INT32:
case OT_UINT32:
pntVal = "<number>";
break;
case OT_UCHAR:
pntVal = "<0-9 | a-z>";
default:
break;
}
const char* sname = OPTION_sname(od);
const char* lname = OPTION_lname(od);
size_t sz = 0;
Opts.optionsLog() += "\t";
if (OPTION_form(od) == OFA_NORMAL) {
for (int j = 0; j < 2; ++j) {
if (j == 0) {
// Short Name
if (sname != NULL) {
Opts.optionsLog() += "-";
Opts.optionsLog() += sname;
} else {
continue;
}
} else { // j == 1
// Long name
if (lname != NULL) {
Opts.optionsLog() += (sname != NULL) ? " --" : "--";
Opts.optionsLog() += lname;
} else {
continue;
}
}
switch (i) {
case OID_PP_D:
Opts.optionsLog() += " name[=<definition>]";
break;
case OID_PP_I:
Opts.optionsLog() += " dir";
break;
default:
if ((OPTION_value(od) == OVA_OPTIONAL) || (OPTION_value(od) == OVA_REQUIRED)) {
if (OPTION_value(od) == OVA_OPTIONAL) {
Opts.optionsLog() += "[";
}
if ((OPTION_info(od) & OA_SEPARATOR_NONE) &&
(OPTION_info(od) & (OA_SEPARATOR_EQUAL | OA_SEPARATOR_SPACE))) {
if ((OPTION_info(od) & OA_SEPARATOR_EQUAL) &&
(OPTION_info(od) & OA_SEPARATOR_SPACE)) {
Opts.optionsLog() += "[ |=]";
} else if (OPTION_info(od) & OA_SEPARATOR_EQUAL) {
Opts.optionsLog() += "[=]";
} else if (OPTION_info(od) & OA_SEPARATOR_SPACE) {
Opts.optionsLog() += "[ ]";
}
} else if (OPTION_info(od) & (OA_SEPARATOR_EQUAL | OA_SEPARATOR_SPACE)) {
if ((OPTION_info(od) & OA_SEPARATOR_EQUAL) &&
(OPTION_info(od) & OA_SEPARATOR_SPACE)) {
Opts.optionsLog() += "{ |=}";
} else if (OPTION_info(od) & OA_SEPARATOR_EQUAL) {
Opts.optionsLog() += "=";
} else {
Opts.optionsLog() += " ";
}
}
Opts.optionsLog() += pntVal.c_str();
if (OPTION_value(od) == OVA_OPTIONAL) {
Opts.optionsLog() += "]";
}
}
break;
} // switch
}
} else if ((OPTION_form(od) == OFA_PREFIX_F) || (OPTION_form(od) == OFA_PREFIX_M)) {
char fORm = ((OPTION_form(od) == OFA_PREFIX_F) ? 'f' : 'm');
if (OPTION_type(od) == OT_BOOL) {
Opts.optionsLog() += '-';
Opts.optionsLog() += fORm;
Opts.optionsLog() += "[no-]";
Opts.optionsLog() += sname;
} else {
Opts.optionsLog() += fORm;
Opts.optionsLog() += sname;
if ((OPTION_value(od) == OVA_OPTIONAL) || (OPTION_value(od) == OVA_REQUIRED)) {
assert(!(OPTION_info(od) & OA_SEPARATOR_NONE) &&
(OPTION_info(od) & (OA_SEPARATOR_EQUAL | OA_SEPARATOR_SPACE)) &&
"prefix -f/-m need either ' ' or '=' as value separator");
if ((OPTION_info(od) & OA_SEPARATOR_EQUAL) && (OPTION_info(od) & OA_SEPARATOR_SPACE)) {
Opts.optionsLog() += "{ |=}";
} else if (OPTION_info(od) & OA_SEPARATOR_EQUAL) {
Opts.optionsLog() += "=";
} else {
Opts.optionsLog() += " ";
}
}
}
}
Opts.optionsLog() += "\n\t ";
Opts.optionsLog() += OPTION_desc(od);
Opts.optionsLog() += "\n\n";
}
}
bool setOptionVariable(OptionDescriptor* oDesc, OptionVariables* oVars, int64_t IValue,
const char* SValue) {
char* addr = reinterpret_cast<char*>(oVars) + oDesc->OptionOffset;
if (OPTION_type(oDesc) == OT_BOOL) {
OT_BOOL_t* o = reinterpret_cast<OT_BOOL_t*>(addr);
*o = static_cast<OT_BOOL_t>(IValue != 0);
} else if (OPTION_type(oDesc) == OT_INT32) {
OT_INT32_t* o = reinterpret_cast<OT_INT32_t*>(addr);
*o = static_cast<OT_INT32_t>(IValue);
} else if (OPTION_type(oDesc) == OT_UINT32) {
OT_UINT32_t* o = reinterpret_cast<OT_UINT32_t*>(addr);
*o = static_cast<OT_UINT32_t>(IValue);
} else if (OPTION_type(oDesc) == OT_CSTRING) {
OT_CSTRING_t* o = reinterpret_cast<OT_CSTRING_t*>(addr);
*o = static_cast<OT_CSTRING_t>(SValue);
} else if (OPTION_type(oDesc) == OT_UCHAR) {
OT_UCHAR_t* o = reinterpret_cast<OT_UCHAR_t*>(addr);
*o = static_cast<OT_UCHAR_t>(IValue);
} else {
return false;
}
return true;
}
static bool setOptionVariable(OptionDescriptor* oDesc, OptionVariables* srcOVars,
OptionVariables* dstOVars) {
char* srcAddr = reinterpret_cast<char*>(srcOVars) + oDesc->OptionOffset;
char* dstAddr = reinterpret_cast<char*>(dstOVars) + oDesc->OptionOffset;
if (OPTION_type(oDesc) == OT_BOOL) {
OT_BOOL_t* src = reinterpret_cast<OT_BOOL_t*>(srcAddr);
OT_BOOL_t* dst = reinterpret_cast<OT_BOOL_t*>(dstAddr);
*dst = *src;
} else if (OPTION_type(oDesc) == OT_INT32) {
OT_INT32_t* src = reinterpret_cast<OT_INT32_t*>(srcAddr);
OT_INT32_t* dst = reinterpret_cast<OT_INT32_t*>(dstAddr);
*dst = *src;
} else if (OPTION_type(oDesc) == OT_UINT32) {
OT_UINT32_t* src = reinterpret_cast<OT_UINT32_t*>(srcAddr);
OT_UINT32_t* dst = reinterpret_cast<OT_UINT32_t*>(dstAddr);
*dst = *src;
} else if (OPTION_type(oDesc) == OT_UCHAR) {
OT_UCHAR_t* src = reinterpret_cast<OT_UCHAR_t*>(srcAddr);
OT_UCHAR_t* dst = reinterpret_cast<OT_UCHAR_t*>(dstAddr);
*dst = *src;
} else if (OPTION_type(oDesc) == OT_CSTRING) {
OT_CSTRING_t* src = reinterpret_cast<OT_CSTRING_t*>(srcAddr);
OT_CSTRING_t* dst = reinterpret_cast<OT_CSTRING_t*>(dstAddr);
*dst = *src;
} else {
return false;
}
return true;
}
int getOptionDesc(std::string& options, size_t StartPos, bool IsShortForm, OptionForm oForm,
size_t& EndPos, std::string& Value) {
int option_ndx = -1;
EndPos = std::string::npos;
const int map_ndx = (IsShortForm ? 0 : 1);
size_t sPos = StartPos;
size_t ePos = options.find(' ', sPos);
size_t pos = options.find('=', sPos);
if (pos < ePos) {
ePos = pos;
}
// The following should work even if ePos is npos
size_t len = ePos - sPos;
// Handle the special options-passing option : -W<l>,s0,s1,s2,s3,....sn
// where l is a single letter. And only in this option, comma ',' is treated
// like a separator.
if ((oForm == OFA_NORMAL) && (options.size() > (sPos + 3))) {
char c0 = options[sPos];
char c1 = options[sPos + 1];
char c2 = options[sPos + 2];
if ((c0 == 'W') && (c2 == ',') && (c1 >= 'a') && (c1 <= 'z')) {
ePos = sPos + 3;
len = 3;
}
}
std::string name = options.substr(sPos, len);
std::map<std::string, int>::const_iterator I, IE;
switch (oForm) {
case OFA_NORMAL:
I = OptionNameMap[map_ndx].find(name);
IE = OptionNameMap[map_ndx].end();
break;
case OFA_PREFIX_F:
I = FOptionMap.find(name);
IE = FOptionMap.end();
break;
case OFA_PREFIX_M:
I = MOptionMap.find(name);
IE = MOptionMap.end();
break;
default:
return -1;
}
if (I != IE) {
// found the exact match, that's it!
option_ndx = I->second;
pos = ePos;
} else if (oForm != OFA_NORMAL) {
return -1;
} else {
I = NoneSeparatorOptionMap[map_ndx].begin();
IE = NoneSeparatorOptionMap[map_ndx].end();
size_t len1 = 0;
for (; I != IE; ++I) {
std::string namevalue = I->first;
size_t n = namevalue.size();
if (n >= len) {
// Not substr, skip
continue;
}
if (name.compare(0, n, namevalue) == 0) {
// found the substr
if (n > len1) {
len1 = n;
option_ndx = I->second;
}
}
}
if (len1 == 0) {
// no matching
return -1;
}
pos = sPos + len1;
}
OptionDescriptor* od = &OptDescTable[option_ndx];
if (pos == std::string::npos) {
if (OPTION_value(od) == OVA_REQUIRED) {
// illegal option
return -1;
}
EndPos = pos;
return option_ndx;
}
char next_c = options.at(pos);
bool optionalHasValue =
(OPTION_value(od) == OVA_OPTIONAL) &&
(((OPTION_info(od) & OA_SEPARATOR_EQUAL) && (next_c == '=')) ||
((OPTION_info(od) & OA_SEPARATOR_NONE) && !OPTION_valueSeparator(next_c)));
bool hasValue = (OPTION_value(od) == OVA_REQUIRED) || optionalHasValue;
if (hasValue) {
if ((OPTION_info(od) & OA_SEPARATOR_EQUAL) && (next_c == '=')) {
pos++;
if (pos == options.size()) {
return -1;
}
} else if ((OPTION_info(od) & OA_SEPARATOR_SPACE) && (next_c == ' ')) {
pos = options.find_first_not_of(' ', pos);
} else if ((OPTION_info(od) & OA_SEPARATOR_NONE) && !OPTION_valueSeparator(next_c)) {
;
} else {
// illgel option
return -1;
}
if (pos == std::string::npos) {
return -1;
}
if ((OPTION_type(od) == OT_CSTRING) && options.at(pos) == '"') {
size_t sz = options.size();
if ((pos + 1) >= sz) {
return -1;
}
/* Handle quoted string value */
ePos = options.find('"', pos + 1);
if (ePos == std::string::npos) {
return -1;
}
/* Advance ePos to the next position or npos */
if (ePos + 1 < sz) {
++ePos;
if (options.at(ePos) != ' ') {
return -1;
}
} else {
ePos = std::string::npos;
}
} else {
ePos = options.find(' ', pos);
}
if (OPTION_info(od) & OA_RUNTIME) {
Value = options.substr(pos, ePos - pos);
}
EndPos = ePos;
} else {
if (next_c != ' ') {
return -1;
}
EndPos = pos;
}
return option_ndx;
}
bool processOption(int OptDescTableIx, Options& Opts, const std::string& Value, bool IsPrefixOption,
bool IsOffFlag) {
OptionVariables* ovars = Opts.oVariables;
OptionDescriptor* od = &OptDescTable[OptDescTableIx];
const char* sval = NULL;
int64_t ival = 0;
int otype = OPTION_type(od);
if (Value.size() == 0) {
if (OPTION_value(od) == OVA_OPTIONAL) {
// Get the second default value !
getDefault2(OptDescTableIx, ival, sval);
} else {
if (otype == OT_BOOL) {
// This option may be either OVA_REQUIRED or OVA_DISALLOWED !
ival = (IsOffFlag ? 0 : 1);
} else {
// This option is either OT_CSTRING or OT_{U]INT32, and requires its value!
assert(false && "This option should have a value");
Opts.optionsLog() = "Value is missing\n";
return false;
}
}
} else {
// An explicit value has been provided.
char* p;
unsigned long uval;
switch (otype) {
case OT_CSTRING: {
char* cs = new char[Value.size() + 1];
Value.copy(cs, Value.size());
cs[Value.size()] = 0;
sval = cs;
// Need to remember this and free memory later.
Opts.recordMemoryHandle((char*)sval);
} break;
case OT_UCHAR: {
ival = Value.at(0);
} break;
case OT_INT32:
ival = ::strtol(Value.c_str(), &p, 0);
if (*p != '\0') {
// invalid value
Opts.optionsLog() = "Value is wrong\n";
return false;
}
if ((ival < OPTION_min(od)) || (ival > OPTION_max(od))) {
std::stringstream msg;
msg << "Value should be in [" << (int)OPTION_min(od) << ", " << (int)OPTION_max(od)
<< "]\n";
Opts.optionsLog() = msg.str().c_str();
return false;
}
break;
case OT_UINT32:
case OT_BOOL:
uval = ::strtoul(Value.c_str(), &p, 0);
if (*p != '\0') {
// invalid value
Opts.optionsLog() = "Value is wrong\n";
return false;
}
ival = (int64_t)uval;
if (otype == OT_BOOL) {
if ((ival < 0) || (ival > 1)) {
Opts.optionsLog() = "Value should be either 0 or 1\n";
return false;
}
} else {
// OT_INT32, OT_UINT32
if ((ival < OPTION_min(od)) || (ival > OPTION_max(od))) {
std::stringstream msg;
msg << "Value should be in [" << (int)OPTION_min(od) << ", " << (int)OPTION_max(od)
<< "]\n";
Opts.optionsLog() = msg.str().c_str();
return false;
}
}
break;
default:
break;
}
}
// First, if it is an alias option, special-process it here.
if (OPTION_info(od) & OA_MISC_ALIAS) {
if (!setAliasOptionVariable(OptDescTableIx, Opts, ival, sval)) {
Opts.optionsLog() = "Wrong value for the option (alias)\n";
return false;
}
return true;
}
// Special procesing of an individual option (non-alias option)
OptionDescriptor* tod;
switch ((OptionIdentifier)OptDescTableIx) {
case OID_ShowHelp:
if ((strcmp(sval, "all") != 0) && (strcmp(sval, "support") != 0) &&
(strcmp(sval, "public") != 0)) {
Opts.optionsLog() = "-h/--help only supports values all|support|public\n";
return false;
}
break;
case OID_FiniteMathOnly:
Opts.setFlag(OID_FiniteMathOnly, 1);
tod = &OptDescTable[OID_FiniteMathOnly];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.clangOptions.push_back("-cl-finite-math-only");
break;
case OID_NoSignedZeros:
Opts.setFlag(OID_NoSignedZeros, 1);
tod = &OptDescTable[OID_NoSignedZeros];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.clangOptions.push_back("-cl-no-signed-zeros");
break;
case OID_FastRelaxedMath:
// -cl-fast-relaxed-math implies:
// -cl-finite-math-only
// -cl-unsafe-math-optimizations
Opts.setFlag(OID_FiniteMathOnly, 1);
tod = &OptDescTable[OID_FiniteMathOnly];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.setFlag(OID_UnsafeMathOpt, 1);
tod = &OptDescTable[OID_UnsafeMathOpt];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.clcOptions.append(" -D__FAST_RELAXED_MATH__=1");
Opts.clangOptions.push_back("-D__FAST_RELAXED_MATH__=1");
Opts.clangOptions.push_back("-cl-fast-relaxed-math");
// fall-through to handle UnsafeMathOpt
case OID_UnsafeMathOpt:
// -cl-unsafe-math-optimizations implies
// -cl-no-signed-zeros
// -cl-mad-enable.
Opts.setFlag(OID_NoSignedZeros, 1);
tod = &OptDescTable[OID_NoSignedZeros];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.setFlag(OID_MadEnable, 1);
tod = &OptDescTable[OID_MadEnable];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.clangOptions.push_back("-cl-unsafe-math-optimizations");
break;
case OID_DenormsAreZero:
Opts.setFlag(OID_DenormsAreZero, 1);
tod = &OptDescTable[OID_DenormsAreZero];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.clangOptions.push_back("-cl-denorms-are-zero");
break;
case OID_StricAliasing:
Opts.setFlag(OID_StricAliasing, 1);
tod = &OptDescTable[OID_StricAliasing];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.clangOptions.push_back("-cl-strict-aliasing");
break;
case OID_MadEnable:
Opts.setFlag(OID_MadEnable, 1);
tod = &OptDescTable[OID_MadEnable];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
Opts.clangOptions.push_back("-cl-mad-enable");
break;
case OID_EnableDebug:
Opts.clcOptions.append(" -g");
Opts.clangOptions.push_back("-g");
break;
case OID_SinglePrecisionConstant:
Opts.clcOptions.append(" --single_precision_constant");
Opts.clangOptions.push_back("-cl-single-precision-constant");
break;
case OID_FP32RoundDivideSqrt:
Opts.clcOptions.append(" --precise_fp32_divide_sqrt");
Opts.clangOptions.push_back("-cl-fp32-correctly-rounded-divide-sqrt");
Opts.setFlag(OID_FP32RoundDivideSqrt, 1);
tod = &OptDescTable[OID_FP32RoundDivideSqrt];
(void)setOptionVariable(tod, ovars, (int64_t)1, NULL);
break;
case OID_EnableC99Inline:
if (ival != 0) {
Opts.clangOptions.push_back("-fc99-inline");
}
break;
case OID_DisableAllWarnings:
if (ival != 0) {
Opts.clcOptions.append(" --no_warnings");
Opts.clangOptions.push_back("-w");
}
break;
case OID_WarnToError:
if (ival != 0) {
Opts.clcOptions.append(" --werror");
Opts.clangOptions.push_back("-Werror");
}
break;
case OID_UniformWorkGroupSize:
Opts.clangOptions.push_back("-cl-uniform-work-group-size");
break;
case OID_WorkGrpSize:
// -wgs=x[,y[,z]]. The default for missing part is 1.
if (sval) {
bool isValueWrong = false;
const char* bp = sval;
char* ep = 0;
int dim = 0;
while (*bp) {
uint32_t tval = ::strtoul(bp, &ep, 0);
if (ep != bp) {
if (dim > 2) {
isValueWrong = true;
break;
}
Opts.WorkGroupSize[dim] = tval;
++dim;
if (*ep == ',') {
bp = ep + 1;
} else if (*ep == 0) {
break;
} else {
isValueWrong = true;
break;
}
} else {
isValueWrong = true;
break;
}
}
if (isValueWrong) {
Opts.optionsLog() = "Wrong option value -wgs=";
Opts.optionsLog() += sval;
Opts.optionsLog() += "\n";
return false;
}
// If there are missing dimention, assume it is 1.
for (int i = dim; i < 3; ++i) {
Opts.WorkGroupSize[i] = 1;
}
Opts.setDefaultWGS(false);
}
break;
case OID_OptUseNative:
Opts.llvmOptions.append(" -mllvm -amdgpu-use-native=");
Opts.llvmOptions.append(sval);
break;
case OID_WFComma:
case OID_WBComma:
case OID_WHComma:
if (sval != NULL) {
// we know that sval was new'ed
for (char* p = (char*)sval; *p; ++p) {
if (*p == ',') {
*p = ' ';
}
}
if ((OptionIdentifier)OptDescTableIx == OID_WFComma) {
Opts.clcOptions.append(" ");
Opts.clcOptions.append(sval);
if (strcmp(sval, "--force_disable_spir") && strcmp(sval, "--single_precision_constant") &&
strcmp(sval, "--precise_fp32_divide_sqrt"))
Opts.clangOptions.push_back(sval);
} else if (((OptionIdentifier)OptDescTableIx) == OID_WBComma) {
Opts.llvmOptions.append(" ");
Opts.llvmOptions.append("-mllvm ");
Opts.llvmOptions.append(sval);
} else if (((OptionIdentifier)OptDescTableIx) == OID_WHComma) {
Opts.finalizerOptions.push_back(sval);
}
}
break;
case OID_XLang:
#ifndef SKIP_INTERNAL_OPTION
// Don't expose "-x il | cgil" to mainline
if ((strcmp(sval, "il") == 0) || (strcmp(sval, "cgil") == 0)) {
break;
}
#endif
if ((strcmp(sval, "clc") != 0) && (strcmp(sval, "clc++") != 0) &&
(strcmp(sval, "spir") != 0)) {
Opts.optionsLog() = "-x only supports values clc, clc++ and spir\n";
return false;
}
// ToDo: EDG is not ready to produce SPIR
// do not pass --spir to EDG
if (strcmp(sval, "spir") != 0) {
// clcOptions should be --c++, --c or --spir
// add "--" prefix for clcOptions
Opts.clcOptions.append(" --");
// skip "cl" prefix in the sval for clcOptions
Opts.clcOptions.append(sval + (strcmp(sval, "spir") != 0 ? 2 : 0));
}
break;
case OID_FSanitize:
if (sval != NULL) Opts.clangOptions.push_back("-fsanitize=" + std::string(sval));
break;
default:
break;
}
if (!setOptionVariable(od, ovars, ival, sval)) {
Opts.optionsLog() = "Wrong option value\n";
return false;
}
return true;
}
// the option at "bpos" of the "options" string is an invalid option,
// log the error message into "log"
static void logInvalidOption(std::string& options, size_t bpos, std::string& log,
const std::string& msg) {
size_t epos = options.find_first_of(' ', bpos);
log = "Invalid option: ";
log += options.substr(bpos, (epos == std::string::npos) ? epos : epos - bpos);
log += msg + "\n";
}
} // namespace
namespace amd {
namespace option {
bool parseAllOptions(std::string& options, Options& Opts, bool linkOptsOnly) {
Opts.origOptionStr = options;
OptionVariables* ovars = Opts.oVariables;
OptionDescriptor* od = OptDescTable;
// Initialize all options to the default
for (int i = 0; i < OID_LAST; ++i, ++od) {
if (!OPTIONHasOVariable(od)) {
continue;
}
if (!setOptionVariable(od, ovars, OPTION_default(od), OPTION_defaultstr(od))) {
Opts.optionsLog() = "Internal Error: option processing failed\n";
return false;
}
}
Opts.clangOptions.push_back("-cl-kernel-arg-info");
// Parse options
if (options.empty()) {
Opts.postParseInit();
return true;
}
bool isLibLinkOpts = false; // is this set of options for linking library?
bool firstOpt = true;
for (size_t pos = options.find_first_not_of(' ', 0); pos != std::string::npos;
pos = options.find_first_not_of(" ", pos)) {
bool isShortName = true; // -: short name; --: long name
// For creating option log
size_t bpos = pos;
if (options.at(pos) == '-') {
pos++;
} else {
// options should start with "-"
logInvalidOption(options, bpos, Opts.optionsLog(), " (expected - at the beginning)");
return false;
}
if (options.at(pos) == '-') {
isShortName = false;
pos++;
}
if ((pos == std::string::npos) || OPTION_valueSeparator(options.at(pos))) {
logInvalidOption(options, bpos, Opts.optionsLog(), " (expected an option name)");
return false;
}
bool isPrefix_fno = false;
bool isPrefix_mno = false;
bool isPrefix_option = false;
std::string value;
size_t sPos = pos;
int option_ndx = getOptionDesc(options, sPos, isShortName, OFA_NORMAL, pos, value);
if (option_ndx < 0) {
size_t sPos1;
pos = sPos;
if (options.at(pos) == 'f') {
isPrefix_option = true;
isPrefix_fno = (options.compare(pos + 1, (size_t)3, "no-") == 0);
sPos1 = pos + (isPrefix_fno ? 4 : 1);
option_ndx = getOptionDesc(options, sPos1, isShortName, OFA_PREFIX_F, pos, value);
} else if (options.at(pos) == 'm') {
isPrefix_option = true;
isPrefix_mno = (options.compare(pos + 1, (size_t)3, "no-") == 0);
sPos1 = pos + (isPrefix_mno ? 4 : 1);
option_ndx = getOptionDesc(options, sPos1, isShortName, OFA_PREFIX_M, pos, value);
}
if (option_ndx < 0) {
logInvalidOption(options, bpos, Opts.optionsLog(), "");
return false;
}
}
od = &OptDescTable[option_ndx];
#ifdef SKIP_INTERNAL_OPTION
if (OPTION_vis(od) == OVIS_INTERNAL) {
// Internal options are not support in the product
logInvalidOption(options, bpos, Opts.optionsLog(), "");
return false;
}
#endif
if (!linkOptsOnly && (OPTION_info(od) & OA_CLC)) {
size_t sPos1 = (isShortName ? sPos - 1 : sPos - 2);
std::string oStr = options.substr(sPos1, pos - sPos1);
if (OPTION_info(od) & OA_CLC) {
Opts.clcOptions.append(" " + oStr);
if (!oStr.compare(0, 2, "-D") || !oStr.compare(0, 2, "-I")) {
// strip off the leading whitespaces in macro
// definition and include path. Clang treats
// whitespaces as part of macro and include paths.
size_t vPos1 = oStr.find_first_not_of(" ", 2);
if (vPos1 == std::string::npos) {
// Do not allow blank macro and include directories
logInvalidOption(options, bpos, Opts.optionsLog(), " (expected value)");
return false;
}
std::string vStr = oStr.substr(vPos1, std::string::npos);
if ((vStr.size() > 2) && (vStr.front() == '\"' && vStr.back() == '\"')) {
// Unquote string
vStr = vStr.substr(1, vStr.size() - 2);
}
Opts.clangOptions.push_back(oStr.substr(0, 2) + vStr);
}
}
}
if (linkOptsOnly) {
if (firstOpt) {
isLibLinkOpts = ((OPTION_info(od) & OA_LINK_LIB)) != 0;
firstOpt = false;
}
if (!(OPTION_info(od) & OA_RUNTIME) || (!isLibLinkOpts && !(OPTION_info(od) & OA_LINK_EXE)) ||
(isLibLinkOpts && !(OPTION_info(od) & OA_LINK_LIB))) {
// Do not allow non-link-time options
logInvalidOption(options, bpos, Opts.optionsLog(), " (bad link-time option)");
return false;
}
} else {
if (!(OPTION_info(od) & OA_RUNTIME)) continue;
}
if (!processOption(option_ndx, Opts, value, isPrefix_option, (isPrefix_mno || isPrefix_fno))) {
// Keep the optionsLog set in processOption().
std::string tmpStr("Invalid option: ");
tmpStr += options.substr(bpos, (pos == std::string::npos) ? pos : pos - bpos);
tmpStr += "\n ";
Opts.optionsLog().insert(0, tmpStr);
return false;
}
Opts.setFlag(option_ndx, 1);
}
if (Opts.isOptionSeen(OID_ShowHelp)) {
OT_CSTRING_t* p = reinterpret_cast<OT_CSTRING_t*>(OPTION_var(OID_ShowHelp, ovars));
const char* arg = (const char*)*p;
ShowOptionsHelp(arg, Opts);
}
// Set up llvmargv if llvmOptions is not empty
if (!Opts.llvmOptions.empty()) {
std::string* ostr = &Opts.llvmOptions;
int n;
size_t pos1, pos2;
pos1 = ostr->find_first_not_of(' ');
for (n = 0; pos1 != std::string::npos; ++n) {
pos2 = ostr->find_first_of(' ', pos1);
if (pos2 != std::string::npos) {
pos2 = ostr->find_first_not_of(' ', pos2);
}
pos1 = pos2;
}
if (n > 0) {
char* data = new char[sizeof(char*) * (n + 1) + // for argv[0:n]
ostr->size() + 1]; // for all option chars
char** t_argv = (char**)data;
static char pseudoCmdName[] = "llvmOptCodegen";
t_argv[0] = &pseudoCmdName[0]; // pseudo command name
Opts.setLLVMArgs(n + 1, t_argv);
Opts.recordMemoryHandle(data);
// Initialize all arguments
t_argv++;
data = (char*)(t_argv + n);
int i = 0;
pos1 = ostr->find_first_not_of(' ');
while (pos1 != std::string::npos) {
pos2 = ostr->find_first_of(' ', pos1);
size_t len;
if (pos2 == std::string::npos) {
len = ostr->size() - pos1;
} else {
len = pos2 - pos1;
pos2 = ostr->find_first_not_of(' ', pos2);
}
ostr->copy(data, len, pos1);
data[len] = 0;
t_argv[i++] = data;
data += (len + 1);
pos1 = pos2;
}
}
}
// if the set of options is OA_LINK_LIB options, the "-create-library"
// option should be included
if (linkOptsOnly && isLibLinkOpts && !Opts.isOptionSeen(OID_clCreateLibrary)) {
Opts.optionsLog() =
"Invalid option:"
" library link options used without -create-library";
return false;
}
if (Opts.isOptionSeen(OID_UniformWorkGroupSize) && (strcmp(ovars->CLStd, "CL1.2") == 0)) {
Opts.optionsLog() =
"Invalid option:"
" -cl-uniform-work-group-size is not supported in OpenCL 1.x\n";
return false;
}
Opts.postParseInit();
return true;
}
bool init() {
// Set up Options Map
for (int i = 0; i < OID_LAST; ++i) {
OptionDescriptor* od = &OptDescTable[i];
const char* sname = OPTION_sname(od);
const char* lname = OPTION_lname(od);
// Make sure alias option is initialized correctly.
if (OPTION_info(od) & OA_MISC_ALIAS) {
// alias option must be in runtime group
OPTION_info(od) |= OA_RUNTIME;
assert((OPTION_offset(od) == 0) &&
"Alias option should be RUNTIME option and has offset zero");
}
if (OPTION_form(od) == OFA_NORMAL) {
if (sname != NULL) {
OptionNameMap[0][sname] = i;
}
if (lname != NULL) {
OptionNameMap[1][lname] = i;
}
if (((OPTION_value(od) == OVA_OPTIONAL) || (OPTION_value(od) == OVA_REQUIRED)) &&
(OPTION_info(od) & OA_SEPARATOR_NONE)) {
if (sname != NULL) {
NoneSeparatorOptionMap[0][sname] = i;
}
if (lname != NULL) {
NoneSeparatorOptionMap[1][sname] = i;
}
}
} else if (OPTION_form(od) == OFA_PREFIX_F) {
assert(((OPTION_value(od) == OVA_DISALLOWED) || !(OPTION_info(od) & OA_SEPARATOR_NONE)) &&
(lname == NULL) &&
"-f/-fno- option may not have a long name, and"
"must have a value separator if it requires a value");
FOptionMap[sname] = i;
} else if (OPTION_form(od) == OFA_PREFIX_M) {
assert(((OPTION_value(od) == OVA_DISALLOWED) || !(OPTION_info(od) & OA_SEPARATOR_NONE)) &&
(lname == NULL) &&
"-m/-mno- option may not have a long name, and"
"must have a value separator if it requires a value");
MOptionMap[sname] = i;
}
}
#if 0
std::map <std::string, int>::const_iterator I, IE;
IE = OptionNameMap[0].end();
for (I = OptionNameMap[0].begin(); I != IE; ++I) {
printf (" %s : %d \n", I->first.c_str(), I->second);
}
#endif
return true;
}
bool teardown() { return true; }
OptionDescriptor* getOptDescTable() { return &OptDescTable[0]; }
Options::Options()
: oVariables(NULL),
clcOptions(),
llvmOptions(),
kernelArgAlign(0),
basename_max(0),
OptionsLog(),
llvmargc(0),
llvmargv(NULL),
buildNo(0),
dumpFileRoot(),
currKernelName(NULL),
encryptCode(0),
MemoryHandles(),
libraryType_(amd::LibraryUndefined) {
oVariables = new OptionVariables();
::memset(flags, 0, sizeof(flags));
// Set -1 to use default
WorkGroupSize[0] = -1;
WorkGroupSize[1] = -1;
WorkGroupSize[2] = -1;
UseDefaultWGS = true;
NumAvailGPRs = -1;
sourceFileName_.reserve(1024);
}
Options::~Options() {
for (int i = 0; i < (int)MemoryHandles.size(); ++i) {
delete[] MemoryHandles[i];
}
if (oVariables) {
delete oVariables;
}
}
void Options::postParseInit() {
if (!oVariables->EnableDumpKernel) {
oVariables->DumpFlags = 0;
}
#if 0
// set -march=gpu-64 for clc
if (oVariables->GPU64BitIsa) {
clcOptions.append(" --march=gpu-64");
}
#endif
oVariables->UseJIT = oVariables->ForceJIT || (oVariables->UseJIT && !oVariables->EnableDebug);
#ifdef SKIP_INTERNAL_OPTION
oVariables->DumpFlags &= DUMP_PRODUCT_FLAGS;
#endif
/*
if (oVariables->OptEstNumGPRs == -1) {
oVariables->OptEstNumGPRs = getDefaultGPRs();
}
*/
}
void Options::setPerBuildInfo(const char* val, int encrypt, bool device) {
encryptCode = encrypt;
setDumpFileName(val);
if (device) {
if (useDefaultWGS()) {
WorkGroupSize[0] = 256;
WorkGroupSize[1] = 1;
WorkGroupSize[2] = 1;
}
// Get an estimate number of available GPRs for each thread
// Can do it more precisely. For now, it is okay doing so.
int numWF = 4;
int wfsize = 64;
if (wfsize > 0) {
numWF = WorkGroupSize[0] / wfsize;
}
if (numWF < 2) {
NumAvailGPRs = 128;
} else {
NumAvailGPRs = 256 / numWF;
}
} else {
// Unused for CPU
NumAvailGPRs = -1;
}
}
// HashString - Hash function for strings.
// This is the Bernstein hash function.
static inline unsigned HashString(std::string::const_iterator it, std::string::const_iterator end) {
auto Bernstein = [](unsigned Result, unsigned char c) { return Result * 33 + c; };
return std::accumulate(it, end, 0U, Bernstein);
}
static inline std::string to_string(unsigned number) {
std::ostringstream ss;
ss << number;
return ss.str();
}
static void splitFileName(const std::string& fileName, std::string& path, std::string& baseName) {
std::size_t found = fileName.find_last_of("/\\");
if (found != std::string::npos) {
path = fileName.substr(0, found + 1);
baseName = fileName.substr(found + 1);
} else {
baseName = fileName;
}
}
#ifdef _WIN32
static inline bool isFullPath(const std::string& path) {
size_t found = path.find(":");
return found != std::string::npos;
}
static std::string getValidDumpPath(const std::string& path) {
if (path.empty()) {
return path;
}
std::string validPath;
unsigned long pathname_max = _MAX_PATH;
if (path.size() > pathname_max) {
// On Windows the max file path is 32,767 if you prefix "\\?\" with full path
if (isFullPath(path)) {
const unsigned new_win_path = _MAX_ENV;
// prefix "\\?\"
validPath = "\\\\?\\" + path;
assert(path.size() < new_win_path);
} else {
assert(path.size() < pathname_max);
}
} else
validPath = path;
return validPath;
}
#else
static std::string getValidDumpPath(const std::string& path) {
if (path.empty()) {
return path;
}
const std::string curPath = path + ".";
long pathname_max = pathconf(curPath.c_str(), _PC_PATH_MAX);
assert(pathname_max != -1 && path.size() < static_cast<unsigned long>(pathname_max));
return path;
}
#endif
static std::string getValidDumpBaseName(const std::string& path, const std::string& file,
long basename_max, const std::string& ext) {
if (file.size() + ext.size() < static_cast<unsigned long>(basename_max)) {
return file;
}
// HashString returns unsigned, and the max lengh of unsighed is
// 10 digits, anything over origDigits will be replaced with its hash value
size_t origDigits = basename_max - 10 - ext.size();
std::string truncName = file.substr(0, origDigits);
unsigned hashVal = HashString(file.begin() + origDigits, file.end());
return truncName + to_string(hashVal);
}
void Options::setDumpFileName(const char* val) {
std::string dumpPrefix = oVariables->DumpPrefix;
const size_t pidPos = dumpPrefix.find("%pid%");
if (pidPos != std::string::npos) {
#ifdef _WIN32
const std::int32_t pid = _getpid();
#endif
#ifdef __linux__
const std::int32_t pid = getpid();
#endif
dumpPrefix.replace(pidPos, 5, std::to_string(pid));
}
std::stringstream prefix;
// Replace characters in the file name that are not legal with '_'.
prefix << dumpPrefix << "_" << buildNo << "_" << std::regex_replace(val, std::regex(":"), "_");
dumpFileRoot = prefix.str();
// Check whether the length of path meets the system limits
splitFileName(dumpFileRoot, fullPath, baseName);
fullPath = getValidDumpPath(fullPath);
#ifdef _WIN32
basename_max = FILENAME_MAX;
#endif
#ifdef __linux__
const std::string curPath = fullPath + ".";
basename_max = pathconf(curPath.c_str(), _PC_NAME_MAX);
assert(basename_max != -1);
#endif
if (!fullPath.empty()) {
dumpFileRoot = fullPath + baseName;
} else {
dumpFileRoot = baseName;
}
}
std::string Options::getDumpFileName(const std::string& ext) {
// The length of file name meets the system limits
if (baseName.size() + ext.size() < static_cast<unsigned long>(basename_max)) {
return fullPath + baseName + ext;
}
std::size_t found = ext.find_last_of(".");
std::string kernel_name, extension;
if (found != std::string::npos) {
kernel_name = ext.substr(0, found);
extension = ext.substr(found);
} else {
extension = ext;
}
baseName = getValidDumpBaseName(fullPath, baseName + kernel_name, basename_max, extension);
std::string fullName;
if (!fullPath.empty()) {
fullName = fullPath + baseName + extension;
} else {
fullName = baseName + extension;
}
return fullName;
}
bool Options::isCStrOptionsEqual(const char* cs1, const char* cs2) const {
if ((cs1 != NULL) && (cs2 != NULL)) {
return (strcmp(cs1, cs2) == 0);
} else if ((cs1 == NULL || strcmp(cs1, "") == 0) && (cs2 == NULL || strcmp(cs2, "") == 0)) {
// consider empty string and NULL ptr (no string) as equal
return true;
}
return false;
}
bool Options::equals(const Options& other, bool ignoreClcOptions) const {
OptionVariables* ovars = oVariables;
OptionVariables* ovars2 = other.oVariables;
OptionDescriptor* od = OptDescTable;
for (int i = 0; i < OID_LAST; ++i, ++od) {
if (!OPTIONHasOVariable(od)) {
continue;
}
char* addr = reinterpret_cast<char*>(ovars) + od->OptionOffset;
char* addr2 = reinterpret_cast<char*>(ovars2) + od->OptionOffset;
if (OPTION_type(od) == OT_BOOL) {
OT_BOOL_t* o = reinterpret_cast<OT_BOOL_t*>(addr);
OT_BOOL_t* o2 = reinterpret_cast<OT_BOOL_t*>(addr2);
if (*o != *o2) return false;
} else if (OPTION_type(od) == OT_INT32) {
OT_INT32_t* o = reinterpret_cast<OT_INT32_t*>(addr);
OT_INT32_t* o2 = reinterpret_cast<OT_INT32_t*>(addr2);
if (*o != *o2) return false;
} else if (OPTION_type(od) == OT_UINT32) {
OT_UINT32_t* o = reinterpret_cast<OT_UINT32_t*>(addr);
OT_UINT32_t* o2 = reinterpret_cast<OT_UINT32_t*>(addr2);
if (*o != *o2) return false;
} else if (OPTION_type(od) == OT_CSTRING) {
OT_CSTRING_t* o = reinterpret_cast<OT_CSTRING_t*>(addr);
OT_CSTRING_t* o2 = reinterpret_cast<OT_CSTRING_t*>(addr2);
if (!isCStrOptionsEqual(*o, *o2)) return false;
} else if (OPTION_type(od) == OT_UCHAR) {
OT_UCHAR_t* o = reinterpret_cast<OT_UCHAR_t*>(addr);
OT_UCHAR_t* o2 = reinterpret_cast<OT_UCHAR_t*>(addr2);
if (*o != *o2) return false;
} else {
return false;
}
}
if (!ignoreClcOptions) {
if (clcOptions.compare(other.clcOptions) != 0) {
return false;
}
}
if (llvmOptions.compare(other.llvmOptions) != 0) {
return false;
}
for (size_t i = 0; i < 3; ++i) {
if (WorkGroupSize[i] != other.WorkGroupSize[i]) {
return false;
}
}
if (NumAvailGPRs != other.NumAvailGPRs) {
return false;
}
return true;
}
bool Options::setOptionVariablesAs(const Options& other) {
OptionVariables* srcovars = other.oVariables;
OptionVariables* dstovars = oVariables;
OptionDescriptor* od = OptDescTable;
for (int i = 0; i < OID_LAST; ++i, ++od) {
if (!OPTIONHasOVariable(od)) {
continue;
}
if (!other.isOptionSeen(i)) {
continue;
}
if (!setOptionVariable(od, srcovars, dstovars)) {
optionsLog() = "Wrong option value\n";
return false;
}
}
return true;
}
std::string Options::getStringFromStringVec(std::vector<std::string>& stringVec) {
const char* const delim = " ";
std::ostringstream strstr;
std::copy(stringVec.begin(), stringVec.end(), std::ostream_iterator<std::string>(strstr, delim));
return strstr.str();
}
} // namespace option
} // namespace amd