Check open source core runtime code into perforce. This includes license and README files.

[git-p4: depot-paths = "//depot/stg/hsa/drivers/hsa/runtime/": change = 1249136]
Этот коммит содержится в:
James Edwards (xN/A) TX committed 2016-03-20 15:39:40 -05:00
1 родитель 73d43224e9
Коммит c9ffe0004e
100 files changed
+37877

No files matched your search

+17
Просмотреть файл
@@ -0,0 +1,17 @@
#
# amdhsacode library
#
# This file is expected to be included from top-level CMakeLists.txt.
#
# Dependencies:
# - Compiler definitions
# - elf library
#
# Defines:
# - amdhsacode library and target include directories
file(GLOB sources *.cpp *.hpp)
find_package(LibElf REQUIRED)
add_library(amdhsacode ${sources})
target_include_directories(amdhsacode PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(amdhsacode elf)
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+193
Просмотреть файл
@@ -0,0 +1,193 @@
////////////////////////////////////////////////////////////////////////////////
//
// The University of Illinois/NCSA
// Open Source License (NCSA)
//
// Copyright (c) 2014-2015, Advanced Micro Devices, Inc. All rights reserved.
//
// Developed by:
//
// AMD Research and AMD HSA Software Development
//
// Advanced Micro Devices, Inc.
//
// www.amd.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal with 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:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in
// the documentation and/or other materials provided with the distribution.
// - Neither the names of Advanced Micro Devices, Inc,
// nor the names of its contributors may be used to endorse or promote
// products derived from this Software without specific prior written
// permission.
//
// 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef AMD_HSA_CODE_UTIL_HPP_
#define AMD_HSA_CODE_UTIL_HPP_
#include <cassert>
#include <string>
#include <vector>
#include <iostream>
#ifdef _WIN32
#include <malloc.h>
#else // _WIN32
#include <cstdlib>
#endif // _WIN32
#include "amd_hsa_kernel_code.h"
#include "amd_hsa_elf.h"
#include "hsa.h"
#include "hsa_ext_finalize.h"
#define hsa_error(e) static_cast<hsa_status_t>(e)
#define release_assert(e) \
if (!(e)) { \
std::cerr << __FILE__ << ":"; \
std::cerr << __LINE__ << ":"; \
std::cerr << " Assertion `" << #e << "' failed." << std::endl; \
std::abort(); \
} \
namespace amd {
namespace hsa {
std::string HsaSymbolKindToString(hsa_symbol_kind_t kind);
std::string HsaSymbolLinkageToString(hsa_symbol_linkage_t linkage);
std::string HsaVariableAllocationToString(hsa_variable_allocation_t allocation);
std::string HsaVariableSegmentToString(hsa_variable_segment_t segment);
std::string HsaProfileToString(hsa_profile_t profile);
std::string HsaMachineModelToString(hsa_machine_model_t model);
std::string HsaFloatRoundingModeToString(hsa_default_float_rounding_mode_t mode);
std::string AmdMachineKindToString(amd_machine_kind16_t machine);
std::string AmdFloatRoundModeToString(amd_float_round_mode_t round_mode);
std::string AmdFloatDenormModeToString(amd_float_denorm_mode_t denorm_mode);
std::string AmdSystemVgprWorkitemIdToString(amd_system_vgpr_workitem_id_t system_vgpr_workitem_id);
std::string AmdElementByteSizeToString(amd_element_byte_size_t element_byte_size);
std::string AmdExceptionKindToString(amd_exception_kind16_t exceptions);
std::string AmdPowerTwoToString(amd_powertwo8_t p);
amdgpu_hsa_elf_segment_t AmdHsaElfSectionSegment(amdgpu_hsa_elf_section_t sec);
bool IsAmdHsaElfSectionROData(amdgpu_hsa_elf_section_t sec);
std::string AmdHsaElfSegmentToString(amdgpu_hsa_elf_segment_t seg);
std::string AmdPTLoadToString(uint64_t type);
void PrintAmdKernelCode(std::ostream& out, const amd_kernel_code_t *akc);
void PrintAmdComputePgmRsrcOne(std::ostream& out, amd_compute_pgm_rsrc_one32_t compute_pgm_rsrc1);
void PrintAmdComputePgmRsrcTwo(std::ostream& out, amd_compute_pgm_rsrc_two32_t compute_pgm_rsrc2);
void PrintAmdKernelCodeProperties(std::ostream& out, amd_kernel_code_properties32_t kernel_code_properties);
void PrintAmdControlDirectives(std::ostream& out, const amd_control_directives_t &control_directives);
namespace code_options {
// Space between options (not at the beginning).
std::ostream& space(std::ostream& out);
// Control directive option without value.
struct control_directive {
const char *name;
control_directive(const char* name_) : name(name_) { }
};
std::ostream& operator<<(std::ostream& out, const control_directive& d);
// Exceptions mask string.
struct exceptions_mask {
uint16_t mask;
exceptions_mask(uint16_t mask_) : mask(mask_) { }
};
std::ostream& operator<<(std::ostream& out, const exceptions_mask& e);
// Control directives options.
struct control_directives {
const hsa_ext_control_directives_t& d;
control_directives(const hsa_ext_control_directives_t& d_) : d(d_) { }
};
std::ostream& operator<<(std::ostream& out, const control_directives& cd);
}
const char* hsaerr2str(hsa_status_t status);
bool ReadFileIntoBuffer(const std::string& filename, std::vector<char>& buffer);
// Create new empty temporary file that will be deleted when closed.
int OpenTempFile(const char* prefix);
void CloseTempFile(int fd);
// Helper comment types for isa disassembler
enum DumpIsaCommentType {
COMMENT_AMD_KERNEL_CODE_T_BEGIN = 1,
COMMENT_AMD_KERNEL_CODE_T_END,
COMMENT_KERNEL_ISA_BEGIN,
};
// Callbacks to create helper comments for isa disassembler
const char * CommentTopCallBack(void *ctx, int type);
const char * CommentRightCallBack(void *ctx, int type);
// Parse disassembler instruction line to find offset
uint32_t ParseInstructionOffset(const std::string& instruction);
// Trim whitespaces from start of string
void ltrim(std::string &str);
// Helper function that allocates an aligned memory.
inline void*
alignedMalloc(size_t size, size_t alignment)
{
#if defined(_WIN32)
return ::_aligned_malloc(size, alignment);
#else
void * ptr = NULL;
alignment = (std::max)(alignment, sizeof(void*));
if (0 == ::posix_memalign(&ptr, alignment, size)) {
return ptr;
}
return NULL;
#endif
}
// Helper function that frees an aligned memory.
inline void
alignedFree(void *ptr)
{
#if defined(_WIN32)
::_aligned_free(ptr);
#else
free(ptr);
#endif
}
inline uint64_t alignUp(uint64_t num, uint64_t align)
{
assert(align);
assert((align & (align - 1)) == 0);
return (num + align - 1) & ~(align - 1);
}
inline uint32_t alignUp(uint32_t num, uint32_t align)
{
assert(align);
assert((align & (align - 1)) == 0);
return (num + align - 1) & ~(align - 1);
}
}
}
#endif // AMD_HSA_CODE_UTIL_HPP_
+94
Просмотреть файл
@@ -0,0 +1,94 @@
////////////////////////////////////////////////////////////////////////////////
//
// The University of Illinois/NCSA
// Open Source License (NCSA)
//
// Copyright (c) 2014-2015, Advanced Micro Devices, Inc. All rights reserved.
//
// Developed by:
//
// AMD Research and AMD HSA Software Development
//
// Advanced Micro Devices, Inc.
//
// www.amd.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal with 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:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in
// the documentation and/or other materials provided with the distribution.
// - Neither the names of Advanced Micro Devices, Inc,
// nor the names of its contributors may be used to endorse or promote
// products derived from this Software without specific prior written
// permission.
//
// 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////
#include "amd_hsa_locks.hpp"
namespace amd {
namespace hsa {
namespace common {
void ReaderWriterLock::ReaderLock()
{
internal_lock_.lock();
while (0 < writers_count_) {
readers_condition_.wait(internal_lock_);
}
readers_count_ += 1;
internal_lock_.unlock();
}
void ReaderWriterLock::ReaderUnlock()
{
internal_lock_.lock();
readers_count_ -= 1;
if (0 == readers_count_ && 0 < writers_waiting_) {
writers_condition_.notify_one();
}
internal_lock_.unlock();
}
void ReaderWriterLock::WriterLock()
{
internal_lock_.lock();
writers_waiting_ += 1;
while (0 < readers_count_ || 0 < writers_count_) {
writers_condition_.wait(internal_lock_);
}
writers_count_ += 1;
writers_waiting_ -= 1;
internal_lock_.unlock();
}
void ReaderWriterLock::WriterUnlock()
{
internal_lock_.lock();
writers_count_ -= 1;
if (0 < writers_waiting_) {
writers_condition_.notify_one();
}
readers_condition_.notify_all();
internal_lock_.unlock();
}
} // namespace common
} // namespace hsa
} // namespace amd
+127
Просмотреть файл
@@ -0,0 +1,127 @@
////////////////////////////////////////////////////////////////////////////////
//
// The University of Illinois/NCSA
// Open Source License (NCSA)
//
// Copyright (c) 2014-2015, Advanced Micro Devices, Inc. All rights reserved.
//
// Developed by:
//
// AMD Research and AMD HSA Software Development
//
// Advanced Micro Devices, Inc.
//
// www.amd.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal with 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:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in
// the documentation and/or other materials provided with the distribution.
// - Neither the names of Advanced Micro Devices, Inc,
// nor the names of its contributors may be used to endorse or promote
// products derived from this Software without specific prior written
// permission.
//
// 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef AMD_HSA_LOCKS_HPP
#define AMD_HSA_LOCKS_HPP
#include <condition_variable>
#include <cstddef>
#include <mutex>
namespace amd {
namespace hsa {
namespace common {
template<typename LockType>
class ReaderLockGuard final {
public:
explicit ReaderLockGuard(LockType &lock):
lock_(lock)
{
lock_.ReaderLock();
}
~ReaderLockGuard()
{
lock_.ReaderUnlock();
}
private:
ReaderLockGuard(const ReaderLockGuard&);
ReaderLockGuard& operator=(const ReaderLockGuard&);
LockType &lock_;
};
template<typename LockType>
class WriterLockGuard final {
public:
explicit WriterLockGuard(LockType &lock):
lock_(lock)
{
lock_.WriterLock();
}
~WriterLockGuard()
{
lock_.WriterUnlock();
}
private:
WriterLockGuard(const WriterLockGuard&);
WriterLockGuard& operator=(const WriterLockGuard&);
LockType &lock_;
};
class ReaderWriterLock final {
public:
ReaderWriterLock():
readers_count_(0), writers_count_(0), writers_waiting_(0) {}
~ReaderWriterLock() {}
void ReaderLock();
void ReaderUnlock();
void WriterLock();
void WriterUnlock();
private:
ReaderWriterLock(const ReaderWriterLock&);
ReaderWriterLock& operator=(const ReaderWriterLock&);
size_t readers_count_;
size_t writers_count_;
size_t writers_waiting_;
std::mutex internal_lock_;
std::condition_variable_any readers_condition_;
std::condition_variable_any writers_condition_;
};
} // namespace common
} // namespace hsa
} // namespace amd
#endif // AMD_HSA_LOCKS_HPP
+340
Просмотреть файл
@@ -0,0 +1,340 @@
////////////////////////////////////////////////////////////////////////////////
//
// The University of Illinois/NCSA
// Open Source License (NCSA)
//
// Copyright (c) 2014-2015, Advanced Micro Devices, Inc. All rights reserved.
//
// Developed by:
//
// AMD Research and AMD HSA Software Development
//
// Advanced Micro Devices, Inc.
//
// www.amd.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal with 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:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in
// the documentation and/or other materials provided with the distribution.
// - Neither the names of Advanced Micro Devices, Inc,
// nor the names of its contributors may be used to endorse or promote
// products derived from this Software without specific prior written
// permission.
//
// 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////
#include "amd_options.hpp"
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <list>
#include <string>
#include <cstddef>
namespace amd {
namespace options {
//===----------------------------------------------------------------------===//
// StringFactory. //
//===----------------------------------------------------------------------===//
std::string StringFactory::Flatten(const char **cstrs,
const uint32_t &cstrs_count,
const char &spacer) {
if (NULL == cstrs || 0 == cstrs_count) {
return std::string();
}
std::string flattened;
for (uint32_t i = 0; i < cstrs_count; ++i) {
if (NULL == cstrs[i]) {
return std::string();
}
flattened += cstrs[i];
if (i != (cstrs_count - 1)) {
flattened += spacer;
}
}
return flattened;
}
std::list<std::string> StringFactory::Tokenize(const char *cstr,
const char &delim) {
if (NULL == cstr) {
return std::list<std::string>();
}
const std::string str = cstr;
size_t start = 0;
size_t end = 0;
std::list<std::string> tokens;
while ((end = str.find(delim, start)) != std::string::npos) {
if (start != end) {
tokens.push_back(str.substr(start, end - start));
}
start = end + 1;
}
if (str.size() > start) {
tokens.push_back(str.substr(start));
}
return tokens;
}
std::string StringFactory::ToLower(const std::string& str) {
std::string lower(str.length(), ' ');
std::transform(str.begin(), str.end(), lower.begin(), ::tolower);
return lower;
}
std::string StringFactory::ToUpper(const std::string& str) {
std::string upper(str.length(), ' ');
std::transform(str.begin(), str.end(), upper.begin(), ::toupper);
return upper;
}
//===----------------------------------------------------------------------===//
// HelpPrinter, HelpStreambuf. //
//===----------------------------------------------------------------------===//
HelpStreambuf::HelpStreambuf(std::ostream& stream)
: basicStream_(&stream),
basicBuf_(stream.rdbuf()),
wrapWidth_(0),
indentSize_(0),
atLineStart_(true),
lineWidth_(0)
{
basicStream_->rdbuf(this);
}
HelpStreambuf::int_type HelpStreambuf::overflow(HelpStreambuf::int_type ch) {
if (atLineStart_ && ch != '\n') {
std::string indent(indentSize_, ' ');
basicBuf_->sputn(indent.data(), indent.size());
lineWidth_ = indentSize_;
atLineStart_ = false;
} else if (ch == '\n') {
atLineStart_ = true;
lineWidth_ = 0;
}
if (wrapWidth_ > 0 && lineWidth_ == wrapWidth_) {
basicBuf_->sputc('\n');
std::string indent(indentSize_, ' ');
basicBuf_->sputn(indent.data(), indent.size());
lineWidth_ = indentSize_;
atLineStart_ = false;
}
lineWidth_++;
return basicBuf_->sputc(ch);
}
HelpPrinter& HelpPrinter::PrintUsage(const std::string& usage) {
sbuf_.IndentSize(0);
sbuf_.WrapWidth(0);
Stream() << usage;
if (usage.length() < USAGE_WIDTH) {
Stream() << std::string(USAGE_WIDTH - usage.length(), ' ');
}
Stream() << std::string(PADDING_WIDTH, ' ');
return *this;
}
HelpPrinter& HelpPrinter::PrintDescription(const std::string& description) {
sbuf_.WrapWidth(USAGE_WIDTH + PADDING_WIDTH + DESCRIPTION_WIDTH);
sbuf_.IndentSize(USAGE_WIDTH + PADDING_WIDTH);
Stream() << description << std::endl;
sbuf_.IndentSize(0);
sbuf_.WrapWidth(0);
return *this;
}
//===----------------------------------------------------------------------===//
// ChoiceOptioin. //
//===----------------------------------------------------------------------===//
ChoiceOption::ChoiceOption(const std::string& name,
const std::vector<std::string>& choices,
const std::string& help,
std::ostream& error)
: OptionBase(name, help, error) {
for (const auto& choice: choices) {
choices_.insert(choice);
}
}
bool ChoiceOption::ProcessTokens(std::list<std::string> &tokens) {
assert(0 == name_.compare(tokens.front()) && "option name is mismatched");
if (2 != tokens.size()) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
tokens.pop_front();
if (0 == choices_.count(tokens.front())) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
is_set_ = true;
value_ = tokens.front();
tokens.pop_front();
return true;
}
void ChoiceOption::PrintHelp(HelpPrinter& printer) const {
std::string usage = "-" + name_ + "=[";
bool first = true;
for (const auto& choice: choices_) {
if (!first) {
usage += '|';
} else {
first = false;
}
usage += choice;
}
usage += "]";
printer.PrintUsage(usage).PrintDescription(help_);
}
//===----------------------------------------------------------------------===//
// OptionParser. //
//===----------------------------------------------------------------------===//
std::vector<OptionBase*>::iterator
OptionParser::FindOption(const std::string& name) {
std::vector<OptionBase*>::iterator it = options_.begin();
std::vector<OptionBase*>::iterator end = options_.end();
for (; it != end; ++it) {
if ((*it)->name() == name) {
return it;
}
}
return end;
}
bool OptionParser::AddOption(OptionBase *option) {
if (NULL == option || !option->IsValid()) {
return false;
}
if (FindOption(option->name()) != options_.end()) {
return false;
}
options_.push_back(option);
return true;
}
const std::string& OptionParser::Unknown() const {
assert(collectUnknown_);
return unknownOptions_;
}
bool OptionParser::ParseOptions(const char *options) {
std::list<std::string> tokens_l1 = StringFactory::Tokenize(options, ' ');
if (0 == tokens_l1.size()) {
return true;
}
std::list<std::string>::iterator tokens_l1i = tokens_l1.begin();
while (tokens_l1i != tokens_l1.end()) {
if ('-' == tokens_l1i->at(0)) {
std::list<std::string>::iterator option_begin = tokens_l1i;
std::list<std::string> tokens_l2;
do {
tokens_l2.push_back(*tokens_l1i);
tokens_l1i++;
} while (tokens_l1i != tokens_l1.end() && '-' != tokens_l1i->at(0));
std::list<std::string>::iterator option_end = tokens_l1i;
tokens_l2.front().erase(0, 1);
if (1 == tokens_l2.size()) {
tokens_l2 = StringFactory::Tokenize(tokens_l2.front().c_str(), '=');
if (2 < tokens_l2.size()) {
if (collectUnknown_) {
unknownOptions_ += *tokens_l1i + " ";
continue;
} else {
error() << "error: invalid option format: \'"
<< tokens_l2.front() << '\'' << std::endl;
Reset();
return false;
}
}
}
auto find_status = FindOption(tokens_l2.front());
if (find_status == options_.end()) {
if (collectUnknown_) {
for (; option_begin != option_end; ++option_begin) {
unknownOptions_ += *option_begin + " ";
}
continue;
} else {
error() << "error: unknown option: \'"
<< tokens_l2.front() << '\'' << std::endl;
Reset();
return false;
}
}
if (!(*find_status)->ProcessTokens(tokens_l2)) {
Reset();
return false;
}
assert(0 == tokens_l2.size());
} else {
if (collectUnknown_) {
unknownOptions_ += *tokens_l1i + " ";
} else {
error() << "error: unknown option: \'"
<< *tokens_l1i << '\'' << std::endl;
Reset();
return false;
}
}
}
return true;
}
void OptionParser::PrintHelp(std::ostream& out, const std::string& addition) const {
HelpPrinter printer(out);
for (const auto& option: options_) {
option->PrintHelp(printer);
}
out << addition << std::endl;
}
void OptionParser::Reset() {
unknownOptions_.clear();
for (auto &option : options_) {
option->Reset();
}
}
} // namespace options
} // namespace amd
+430
Просмотреть файл
@@ -0,0 +1,430 @@
////////////////////////////////////////////////////////////////////////////////
//
// The University of Illinois/NCSA
// Open Source License (NCSA)
//
// Copyright (c) 2014-2015, Advanced Micro Devices, Inc. All rights reserved.
//
// Developed by:
//
// AMD Research and AMD HSA Software Development
//
// Advanced Micro Devices, Inc.
//
// www.amd.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal with 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:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in
// the documentation and/or other materials provided with the distribution.
// - Neither the names of Advanced Micro Devices, Inc,
// nor the names of its contributors may be used to endorse or promote
// products derived from this Software without specific prior written
// permission.
//
// 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef AMD_OPTIONS_HPP
#define AMD_OPTIONS_HPP
#include <cstdlib>
#include <iostream>
#include <list>
#include <vector>
#include <cstdint>
#include <cassert>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
namespace amd {
namespace options {
//===----------------------------------------------------------------------===//
// StringFactory. //
//===----------------------------------------------------------------------===//
class StringFactory final {
public:
static std::string Flatten(const char **cstrs,
const uint32_t &cstrs_count,
const char &spacer = '\0');
static std::list<std::string> Tokenize(const char *cstr, const char &delim);
static std::string ToLower(const std::string& str);
static std::string ToUpper(const std::string& str);
};
//===----------------------------------------------------------------------===//
// HelpPrinter, HelpStreambuf. //
//===----------------------------------------------------------------------===//
class HelpStreambuf : public std::streambuf {
public:
explicit HelpStreambuf(std::ostream& stream);
virtual ~HelpStreambuf() {
basicStream_->rdbuf(basicBuf_);
}
void IndentSize(unsigned indent) {
assert(wrapWidth_ == 0 || indentSize_ < wrapWidth_);
indentSize_ = indent;
}
void WrapWidth(unsigned wrap) {
assert(wrapWidth_ == 0 || indentSize_ < wrapWidth_);
wrapWidth_ = wrap;
}
protected:
virtual int_type overflow(int_type ch) override;
private:
std::ostream* basicStream_;
std::streambuf* basicBuf_;
unsigned wrapWidth_;
unsigned indentSize_;
bool atLineStart_;
unsigned lineWidth_;
};
class HelpPrinter {
private:
static const unsigned USAGE_WIDTH = 30;
static const unsigned PADDING_WIDTH = 2;
static const unsigned DESCRIPTION_WIDTH = 50;
public:
HelpPrinter& PrintUsage(const std::string& usage);
HelpPrinter& PrintDescription(const std::string& description);
std::ostream& Stream() { return *out_; }
private:
explicit HelpPrinter(std::ostream& out = std::cout) : out_(&out), sbuf_(*out_) {}
/// @brief Not copy-constructible.
HelpPrinter(const HelpPrinter&);
/// @brief Not copy-assignable.
HelpPrinter& operator =(const HelpPrinter&);
friend class OptionParser;
std::ostream *out_;
HelpStreambuf sbuf_;
};
//===----------------------------------------------------------------------===//
// OptionBase. //
//===----------------------------------------------------------------------===//
class OptionBase {
public:
virtual ~OptionBase() {}
const std::string& name() const {
return name_;
}
const bool& is_set() const {
return is_set_;
}
bool IsValid() const {
return 0 < name_.size();
}
protected:
explicit OptionBase(const std::string& name,
const std::string& help = "",
std::ostream &error = std::cerr)
: name_(name),
help_(help),
is_set_(false),
error_(&error) {}
virtual void PrintHelp(HelpPrinter& printer) const = 0;
const std::string name_;
const std::string help_;
bool is_set_;
std::ostream &error() const { return *error_; }
private:
/// @brief Not copy-constructible.
OptionBase(const OptionBase &ob);
/// @brief Not copy-assignable.
OptionBase& operator=(const OptionBase &ob);
void Reset() {
is_set_ = false;
}
virtual bool ProcessTokens(std::list<std::string> &tokens) = 0;
friend class OptionParser;
mutable std::ostream *error_;
};
//===----------------------------------------------------------------------===//
// Option<T>. //
//===----------------------------------------------------------------------===//
template<typename T>
class Option final: public OptionBase {
public:
explicit Option(const std::string& name,
const std::string& help = "",
std::ostream& error = std::cerr):
OptionBase(name, help, error) {}
~Option() {}
const std::list<T>& values() const {
return values_;
}
protected:
virtual void PrintHelp(HelpPrinter& printer) const override;
private:
/// @brief Not copy-constructible.
Option(const Option &o);
/// @brief Not copy-assignable.
Option& operator=(const Option &o);
bool ProcessTokens(std::list<std::string> &tokens);
std::list<T> values_;
};
template<typename T>
bool Option<T>::ProcessTokens(std::list<std::string> &tokens) {
assert(0 == name_.compare(tokens.front()) && "option name is mismatched");
if (2 > tokens.size()) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
is_set_ = true;
tokens.pop_front();
while (!tokens.empty()) {
std::istringstream token_stream(tokens.front());
if (!token_stream.good()) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
T value;
token_stream >> value;
values_.push_back(value);
tokens.pop_front();
}
return true;
}
template<typename T>
void Option<T>::PrintHelp(HelpPrinter& printer) const {
printer.PrintUsage("-" + name_ + " [" + StringFactory::ToUpper(name_) + "s]")
.PrintDescription(help_);
}
//===----------------------------------------------------------------------===//
// ValueOption<T>. //
//===----------------------------------------------------------------------===//
template<typename T>
class ValueOption final: public OptionBase {
public:
explicit ValueOption(const std::string& name,
const std::string& help = "",
std::ostream& error = std::cerr):
OptionBase(name, help, error) {}
~ValueOption() {}
const T& value() const {
return value_;
}
protected:
void PrintHelp(HelpPrinter& printer) const override;
private:
/// @brief Not copy-constructible.
ValueOption(const ValueOption &o);
/// @brief Not copy-assignable.
ValueOption& operator=(const ValueOption &o);
bool ProcessTokens(std::list<std::string> &tokens);
T value_;
};
template<typename T>
bool ValueOption<T>::ProcessTokens(std::list<std::string> &tokens) {
assert(0 == name_.compare(tokens.front()) && "option name is mismatched");
if (2 != tokens.size()) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
is_set_ = true;
tokens.pop_front();
std::istringstream token_stream(tokens.front());
if (!token_stream.good()) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
token_stream >> value_;
tokens.pop_front();
return true;
}
template<typename T>
void ValueOption<T>::PrintHelp(HelpPrinter& printer) const {
printer.PrintUsage("-" + name_ + "=[VAL]")
.PrintDescription(help_);
}
//===----------------------------------------------------------------------===//
// ChoiceOptioin. //
//===----------------------------------------------------------------------===//
class ChoiceOption final: public OptionBase {
public:
ChoiceOption(const std::string& name,
const std::vector<std::string>& choices,
const std::string& help = "",
std::ostream& error = std::cerr);
~ChoiceOption() {}
const std::string& value() const {
return value_;
}
protected:
void PrintHelp(HelpPrinter& printer) const override;
private:
/// @brief Not copy-constructible.
ChoiceOption(const ChoiceOption&);
/// @brief Not copy-assignable.
ChoiceOption& operator =(const ChoiceOption&);
bool ProcessTokens(std::list<std::string> &tokens);
std::unordered_set<std::string> choices_;
std::string value_;
};
//===----------------------------------------------------------------------===//
// Option<void>. //
//===----------------------------------------------------------------------===//
class NoArgOption final: public OptionBase {
public:
explicit NoArgOption(const std::string& name,
const std::string& help = "",
std::ostream& error = std::cerr):
OptionBase(name, help, error) {}
~NoArgOption() {}
protected:
void PrintHelp(HelpPrinter& printer) const override {
printer.PrintUsage("-" + name_).PrintDescription(help_);
}
private:
/// @brief Not copy-constructible.
NoArgOption(const NoArgOption &o);
/// @brief Not copy-assignable.
NoArgOption& operator=(const NoArgOption &o);
bool ProcessTokens(std::list<std::string> &tokens) {
assert(0 == name_.compare(tokens.front()) && "option name is mismatched");
if (1 != tokens.size()) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
is_set_ = true;
tokens.pop_front();
return true;
}
};
//===----------------------------------------------------------------------===//
// OptionParser. //
//===----------------------------------------------------------------------===//
class OptionParser final {
public:
explicit OptionParser(bool collectUnknown = false, std::ostream& error = std::cerr)
: collectUnknown_(collectUnknown),
error_(&error) {}
~OptionParser() {}
bool AddOption(OptionBase *option);
bool ParseOptions(const char *options);
const std::string& Unknown() const;
void CollectUnknown(bool b) { collectUnknown_ = b; }
void PrintHelp(std::ostream& out, const std::string& addition = "") const;
void Reset();
private:
/// @brief Not copy-constructible.
OptionParser(const OptionParser &op);
/// @brief Not copy-assignable.
OptionParser& operator=(const OptionParser &op);
std::ostream& error() { return *error_; }
std::vector<OptionBase*>::iterator FindOption(const std::string& name);
std::vector<OptionBase*> options_;
std::string unknownOptions_;
bool collectUnknown_;
std::ostream *error_;
};
} // namespace options
} // namespace amd
#endif // AMD_OPTIONS_HPP