6cf55651a5
ECR #333753 - Fix for 1.2 conformance compiler options_include_directory test. Added code to pass -I<include_path> option to clang.
Affected files ...
... //depot/stg/opencl/drivers/opencl/compiler/lib/utils/options.cpp#28 edit
[ROCm/clr commit: fe4d2c12a1]
1593 라인
49 KiB
C++
1593 라인
49 KiB
C++
//
|
|
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
|
//
|
|
|
|
#include <string>
|
|
#include <map>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <sstream>
|
|
#include <cassert>
|
|
#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];
|
|
std::map <std::string, int> NoneSeparatorOptionMap[2];
|
|
std::map <std::string, int> FOptionMap; // prefix -f/-fno- options
|
|
std::map <std::string, int> MOptionMap; // prefix -m/-mno- options
|
|
|
|
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 = 3;
|
|
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)0, 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)) {
|
|
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;
|
|
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 {
|
|
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_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_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_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");
|
|
|
|
// 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);
|
|
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_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_WFComma:
|
|
case OID_WBComma:
|
|
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(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;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// 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 name, 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);
|
|
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()
|
|
{
|
|
OptionNameMap[0].clear();
|
|
OptionNameMap[1].clear();
|
|
NoneSeparatorOptionMap[0].clear();
|
|
NoneSeparatorOptionMap[1].clear();
|
|
FOptionMap.clear();
|
|
MOptionMap.clear();
|
|
return true;
|
|
}
|
|
|
|
OptionDescriptor*
|
|
getOptDescTable()
|
|
{
|
|
return &OptDescTable[0];
|
|
}
|
|
|
|
Options::Options() :
|
|
oVariables(NULL),
|
|
clcOptions(),
|
|
llvmOptions(),
|
|
basename_max(0),
|
|
OptionsLog(),
|
|
flagsSize (((OID_LAST + 31)/32) * 32),
|
|
llvmargc(0),
|
|
llvmargv(NULL),
|
|
buildNo(0),
|
|
dumpFileRoot(),
|
|
currKernelName(NULL),
|
|
encryptCode(0),
|
|
MemoryHandles()
|
|
{
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
static inline bool isFullPath(const std::string &path)
|
|
{
|
|
size_t found = path.find(":");
|
|
return found != std::string::npos;
|
|
}
|
|
|
|
// HashString - Hash function for strings.
|
|
// This is the Bernstein hash function.
|
|
static inline unsigned HashString(std::string Str, unsigned Result = 0)
|
|
{
|
|
for (size_t i = 0, e = Str.size(); i != e; ++i) {
|
|
Result = Result * 33 + (unsigned char)Str[i];
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
static std::string getValidDumpPath(const std::string &path)
|
|
{
|
|
if (path.empty()) {
|
|
return path;
|
|
}
|
|
|
|
#ifdef __linux__
|
|
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
|
|
#ifdef _WIN32
|
|
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;
|
|
#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;
|
|
}
|
|
|
|
std::string truncName;
|
|
// 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();
|
|
truncName = file.substr(0, origDigits);
|
|
std::string remainStr = file.substr(origDigits);
|
|
unsigned hashVal = HashString(remainStr);
|
|
|
|
return truncName + to_string(hashVal);
|
|
}
|
|
|
|
void
|
|
Options::setDumpFileName(const char* val)
|
|
{
|
|
std::stringstream prefix;
|
|
prefix << oVariables->DumpPrefix << "_" << buildNo << "_" << val;
|
|
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::isCStrEqual(const char *cs1, const char* cs2)
|
|
{
|
|
if ((cs1 != NULL) && (cs2 != NULL)) {
|
|
return (strcmp(cs1, cs2) == 0);
|
|
}
|
|
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 (*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;
|
|
}
|
|
|
|
} // option
|
|
|
|
}// amd
|
|
|