dep/reshadefx: Update to 7bdfb03

This commit is contained in:
Stenzek
2024-09-08 19:19:58 +10:00
parent 3078339f64
commit 86bff869bc
25 changed files with 6041 additions and 3244 deletions

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

View File

@ -3,16 +3,16 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "effect_lexer.hpp"
#include "effect_codegen.hpp"
#include <cmath> // fmod
#include "effect_expression.hpp"
#include <cmath> // std::fmod
#include <cassert>
#include <cstring> // memcpy, memset
#include <algorithm> // std::min, std::max
#include <cstring> // std::memcpy, std::memset
#include <algorithm> // std::max, std::min
reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs)
{
type result = { std::max(lhs.base, rhs.base) };
type result;
result.base = std::max(lhs.base, rhs.base);
// Non-numeric types cannot be vectors or matrices
if (!result.is_numeric())
@ -35,11 +35,14 @@ reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs)
// Some qualifiers propagate to the result
result.qualifiers = (lhs.qualifiers & type::q_precise) | (rhs.qualifiers & type::q_precise);
// In case this is a structure, assume they are the same
result.definition = rhs.definition;
assert(lhs.definition == rhs.definition || lhs.definition == 0);
// Cannot merge array types, assume no arrays
result.array_length = 0;
assert(lhs.array_length == 0 && rhs.array_length == 0);
// In case this is a structure, assume they are the same
result.struct_definition = rhs.struct_definition;
assert(lhs.struct_definition == rhs.struct_definition || lhs.struct_definition == 0);
return result;
}
@ -48,101 +51,101 @@ std::string reshadefx::type::description() const
std::string result;
switch (base)
{
case reshadefx::type::t_void:
case t_void:
result = "void";
break;
case reshadefx::type::t_bool:
case t_bool:
result = "bool";
break;
case reshadefx::type::t_min16int:
case t_min16int:
result = "min16int";
break;
case reshadefx::type::t_int:
case t_int:
result = "int";
break;
case reshadefx::type::t_min16uint:
case t_min16uint:
result = "min16uint";
break;
case reshadefx::type::t_uint:
case t_uint:
result = "uint";
break;
case reshadefx::type::t_min16float:
case t_min16float:
result = "min16float";
break;
case reshadefx::type::t_float:
case t_float:
result = "float";
break;
case reshadefx::type::t_string:
case t_string:
result = "string";
break;
case reshadefx::type::t_struct:
case t_struct:
result = "struct";
break;
case reshadefx::type::t_texture1d:
case t_texture1d:
result = "texture1D";
break;
case reshadefx::type::t_texture2d:
case t_texture2d:
result = "texture2D";
break;
case reshadefx::type::t_texture3d:
case t_texture3d:
result = "texture3D";
break;
case reshadefx::type::t_sampler1d_int:
case t_sampler1d_int:
result = "sampler1D<int" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_sampler2d_int:
case t_sampler2d_int:
result = "sampler2D<int" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_sampler3d_int:
case t_sampler3d_int:
result = "sampler3D<int" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_sampler1d_uint:
case t_sampler1d_uint:
result = "sampler1D<uint" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_sampler2d_uint:
case t_sampler2d_uint:
result = "sampler2D<uint" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_sampler3d_uint:
case t_sampler3d_uint:
result = "sampler3D<uint" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_sampler1d_float:
case t_sampler1d_float:
result = "sampler1D<float" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_sampler2d_float:
case t_sampler2d_float:
result = "sampler2D<float" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_sampler3d_float:
case t_sampler3d_float:
result = "sampler3D<float" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage1d_int:
case t_storage1d_int:
result = "storage1D<int" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage2d_int:
case t_storage2d_int:
result = "storage2D<int" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage3d_int:
case t_storage3d_int:
result = "storage3D<int" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage1d_uint:
case t_storage1d_uint:
result = "storage1D<uint" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage2d_uint:
case t_storage2d_uint:
result = "storage2D<uint" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage3d_uint:
case t_storage3d_uint:
result = "storage3D<uint" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage1d_float:
case t_storage1d_float:
result = "storage1D<float" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage2d_float:
case t_storage2d_float:
result = "storage2D<float" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_storage3d_float:
case t_storage3d_float:
result = "storage3D<float" + std::to_string(rows) + '>';
break;
case reshadefx::type::t_function:
result = "function";
case t_function:
assert(false);
break;
}
@ -157,7 +160,7 @@ std::string reshadefx::type::description() const
if (is_array())
{
result += '[';
if (array_length > 0)
if (is_bounded_array())
result += std::to_string(array_length);
result += ']';
}
@ -179,7 +182,7 @@ void reshadefx::expression::reset_to_lvalue(const reshadefx::location &loc, uint
type.qualifiers |= type::q_const;
// Strip away global variable qualifiers
type.qualifiers &= ~(reshadefx::type::q_extern | reshadefx::type::q_static | reshadefx::type::q_uniform | reshadefx::type::q_groupshared);
type.qualifiers &= ~(type::q_extern | type::q_static | type::q_uniform | type::q_groupshared);
}
void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint32_t in_base, const reshadefx::type &in_type)
{
@ -192,7 +195,7 @@ void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint
chain.clear();
// Strip away global variable qualifiers
type.qualifiers &= ~(reshadefx::type::q_extern | reshadefx::type::q_static | reshadefx::type::q_uniform | reshadefx::type::q_groupshared);
type.qualifiers &= ~(type::q_extern | type::q_static | type::q_uniform | type::q_groupshared);
}
void reshadefx::expression::reset_to_rvalue_constant(const reshadefx::location &loc, bool data)
@ -290,7 +293,7 @@ void reshadefx::expression::add_cast_operation(const reshadefx::type &cast_type)
constant.as_float[i] = static_cast<float>(constant.as_int[i]);
};
for (auto &element : constant.array_data)
for (struct constant &element : constant.array_data)
cast_constant(element, type, cast_type);
cast_constant(constant, type, cast_type);
@ -320,7 +323,7 @@ void reshadefx::expression::add_dynamic_index_access(uint32_t index_expression)
assert(!is_constant); // Cannot have dynamic indexing into constant in SPIR-V
assert(type.is_array() || (type.is_numeric() && !type.is_scalar()));
auto prev_type = type;
struct type prev_type = type;
if (type.is_array())
{
@ -342,11 +345,11 @@ void reshadefx::expression::add_constant_index_access(unsigned int index)
{
assert(type.is_array() || (type.is_numeric() && !type.is_scalar()));
auto prev_type = type;
struct type prev_type = type;
if (type.is_array())
{
assert(type.array_length < 0 || index < static_cast<unsigned int>(type.array_length));
assert(index < type.array_length);
type.array_length = 0;
}
@ -389,7 +392,7 @@ void reshadefx::expression::add_swizzle_access(const signed char swizzle[4], uns
{
assert(type.is_numeric() && !type.is_array());
const auto prev_type = type;
const struct type prev_type = type;
type.rows = length;
type.cols = 1;

View File

@ -18,7 +18,7 @@ enum token_type
};
// Lookup table which translates a given char to a token type
static const unsigned type_lookup[256] = {
static const unsigned int s_type_lookup[256] = {
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, SPACE,
'\n', SPACE, SPACE, SPACE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -35,7 +35,7 @@ static const unsigned type_lookup[256] = {
};
// Lookup tables which translate a given string literal to a token and backwards
static const std::unordered_map<tokenid, std::string_view> token_lookup = {
static const std::unordered_map<tokenid, std::string_view> s_token_lookup = {
{ tokenid::end_of_file, "end of file" },
{ tokenid::exclaim, "!" },
{ tokenid::hash, "#" },
@ -205,7 +205,7 @@ static const std::unordered_map<tokenid, std::string_view> token_lookup = {
{ tokenid::storage2d, "storage2D" },
{ tokenid::storage3d, "storage3D" },
};
static const std::unordered_map<std::string_view, tokenid> keyword_lookup = {
static const std::unordered_map<std::string_view, tokenid> s_keyword_lookup = {
{ "asm", tokenid::reserved },
{ "asm_fragment", tokenid::reserved },
{ "auto", tokenid::reserved },
@ -439,7 +439,7 @@ static const std::unordered_map<std::string_view, tokenid> keyword_lookup = {
{ "volatile", tokenid::volatile_ },
{ "while", tokenid::while_ }
};
static const std::unordered_map<std::string_view, tokenid> pp_directive_lookup = {
static const std::unordered_map<std::string_view, tokenid> s_pp_directive_lookup = {
{ "define", tokenid::hash_def },
{ "undef", tokenid::hash_undef },
{ "if", tokenid::hash_if },
@ -454,15 +454,15 @@ static const std::unordered_map<std::string_view, tokenid> pp_directive_lookup =
{ "include", tokenid::hash_include },
};
static inline bool is_octal_digit(char c)
static bool is_octal_digit(char c)
{
return static_cast<unsigned>(c - '0') < 8;
}
static inline bool is_decimal_digit(char c)
static bool is_decimal_digit(char c)
{
return static_cast<unsigned>(c - '0') < 10;
}
static inline bool is_hexadecimal_digit(char c)
static bool is_hexadecimal_digit(char c)
{
return is_decimal_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
@ -504,8 +504,8 @@ static long long octal_to_decimal(long long n)
std::string reshadefx::token::id_to_name(tokenid id)
{
const auto it = token_lookup.find(id);
if (it != token_lookup.end())
const auto it = s_token_lookup.find(id);
if (it != s_token_lookup.end())
return std::string(it->second);
return "unknown";
}
@ -526,7 +526,7 @@ next_token:
assert(_cur <= _end);
// Do a character type lookup for the current character
switch (type_lookup[uint8_t(*_cur)])
switch (s_type_lookup[uint8_t(*_cur)])
{
case 0xFF: // EOF
tok.id = tokenid::end_of_file;
@ -635,7 +635,7 @@ next_token:
tok.id = tokenid::minus;
break;
case '.':
if (type_lookup[uint8_t(_cur[1])] == DIGIT)
if (s_type_lookup[uint8_t(_cur[1])] == DIGIT)
parse_numeric_literal(tok);
else if (_cur[1] == '.' && _cur[2] == '.')
tok.id = tokenid::ellipsis,
@ -805,7 +805,7 @@ void reshadefx::lexer::skip_space()
continue;
}
if (type_lookup[uint8_t(*_cur)] == SPACE)
if (s_type_lookup[uint8_t(*_cur)] == SPACE)
skip(1);
else
break;
@ -841,7 +841,7 @@ void reshadefx::lexer::parse_identifier(token &tok) const
auto *const begin = _cur, *end = begin;
// Skip to the end of the identifier sequence
while (type_lookup[uint8_t(*end)] == IDENT || type_lookup[uint8_t(*end)] == DIGIT)
while (s_type_lookup[uint8_t(*end)] == IDENT || s_type_lookup[uint8_t(*end)] == DIGIT)
end++;
tok.id = tokenid::identifier;
@ -852,8 +852,8 @@ void reshadefx::lexer::parse_identifier(token &tok) const
if (_ignore_keywords)
return;
if (const auto it = keyword_lookup.find(tok.literal_as_string);
it != keyword_lookup.end())
if (const auto it = s_keyword_lookup.find(tok.literal_as_string);
it != s_keyword_lookup.end())
tok.id = it->second;
}
bool reshadefx::lexer::parse_pp_directive(token &tok)
@ -862,8 +862,8 @@ bool reshadefx::lexer::parse_pp_directive(token &tok)
skip_space(); // Skip any space between the '#' and directive
parse_identifier(tok);
if (const auto it = pp_directive_lookup.find(tok.literal_as_string);
it != pp_directive_lookup.end())
if (const auto it = s_pp_directive_lookup.find(tok.literal_as_string);
it != s_pp_directive_lookup.end())
{
tok.id = it->second;
return true;
@ -999,6 +999,9 @@ void reshadefx::lexer::parse_string_literal(token &tok, bool escape)
tok.id = tokenid::string_literal;
tok.length = end - begin + 1;
// Free up unused memory
tok.literal_as_string.shrink_to_fit();
}
void reshadefx::lexer::parse_numeric_literal(token &tok) const
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,8 @@
#include "effect_lexer.hpp"
#include "effect_preprocessor.hpp"
#include <cstdio> // fclose, fopen, fread, fseek
#include <cassert>
#include <fstream>
#include <algorithm> // std::find_if
#ifndef _WIN32
@ -52,7 +52,7 @@ enum macro_replacement
macro_replacement_stringize = '\xFE',
};
static const int precedence_lookup[] = {
static const int s_precedence_lookup[] = {
0, 1, 2, 3, 4, // bitwise operators
5, 6, 7, 7, 7, 7, // logical operators
8, 8, // left shift, right shift
@ -61,9 +61,8 @@ static const int precedence_lookup[] = {
11, 11, 11, 11 // unary operators
};
static bool read_file(const std::string &path, std::string &data, reshadefx::preprocessor::include_read_file_callback &cb)
static bool read_file(const std::string &path, std::string &file_data, reshadefx::preprocessor::include_read_file_callback &cb)
{
std::string file_data;
if (!cb(path, file_data))
return false;
@ -77,29 +76,33 @@ static bool read_file(const std::string &path, std::string &data, reshadefx::pre
static_cast<unsigned char>(file_data[2]) == 0xbf)
file_data.erase(0, 3);
data = std::move(file_data);
return true;
}
bool reshadefx::preprocessor::stdfs_read_file_callback(const std::string &path, std::string &data)
{
std::ifstream file(std::filesystem::path(path), std::ios::binary);
if (!file)
return false;
// Read file contents into memory
const std::filesystem::path fspath(path);
#ifndef _WIN32
FILE *const file = fopen(fspath.c_str(), "rb");
#else
FILE *const file = _wfsopen(fspath.generic_wstring().c_str(), L"rb", SH_DENYWR);
#endif
if (file == nullptr)
return false;
// Read file contents into memory
std::error_code ec;
const uintmax_t file_size = std::filesystem::file_size(path, ec);
if (ec)
return false;
fseek(file, 0, SEEK_END);
const size_t file_size = ftell(file);
fseek(file, 0, SEEK_SET);
data.reserve(file_size + 1);
data.resize(static_cast<size_t>(file_size), '\0');
if (!file.read(data.data(), file_size))
return false;
const size_t file_size_read = fread(data.data(), 1, file_size, file);
// No longer need to have a handle open to the file, since all data was read, so can safely close it
fclose(file);
if (file_size_read != file_size)
return false;
// No longer need to have a handle open to the file, since all data was read, so can safely close it
file.close();
return true;
}
@ -156,7 +159,8 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std::
// Enforce all input strings to end with a line feed
assert(!source_code.empty() && source_code.back() == '\n');
_success = true; // Clear success flag before parsing a new string
// Only consider new errors added below for the success of this call
const size_t errors_offset = _errors.length();
// Give this push a name, so that lexer location starts at a new line
// This is necessary in case this string starts with a preprocessor directive, since the lexer only reports those as such if they appear at the beginning of a new line
@ -164,15 +168,15 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std::
push(std::move(source_code), path.empty() ? "unknown" : path);
parse();
return _success;
return _errors.find(": preprocessor error: ", errors_offset) == std::string::npos;
}
std::vector<std::filesystem::path> reshadefx::preprocessor::included_files() const
{
std::vector<std::filesystem::path> files;
files.reserve(_file_cache.size());
for (const auto &it : _file_cache)
files.push_back(std::filesystem::u8path(it.first));
for (const std::pair<std::string, std::string> &cache_entry : _file_cache)
files.push_back(std::filesystem::u8path(cache_entry.first));
return files;
}
std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_macro_definitions() const
@ -189,12 +193,19 @@ std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_m
void reshadefx::preprocessor::error(const location &location, const std::string &message)
{
_errors += location.source + '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')' + ": preprocessor error: " + message + '\n';
_success = false; // Unset success flag
_errors += location.source;
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
_errors += ": preprocessor error: ";
_errors += message;
_errors += '\n';
}
void reshadefx::preprocessor::warning(const location &location, const std::string &message)
{
_errors += location.source + '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')' + ": preprocessor warning: " + message + '\n';
_errors += location.source;
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
_errors += ": preprocessor warning: ";
_errors += message;
_errors += '\n';
}
void reshadefx::preprocessor::push(std::string input, const std::string &name)
@ -357,32 +368,32 @@ void reshadefx::preprocessor::parse()
{
case tokenid::hash_if:
parse_if();
if (!expect(tokenid::end_of_line))
if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line);
continue;
case tokenid::hash_ifdef:
parse_ifdef();
if (!expect(tokenid::end_of_line))
if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line);
continue;
case tokenid::hash_ifndef:
parse_ifndef();
if (!expect(tokenid::end_of_line))
if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line);
continue;
case tokenid::hash_else:
parse_else();
if (!expect(tokenid::end_of_line))
if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line);
continue;
case tokenid::hash_elif:
parse_elif();
if (!expect(tokenid::end_of_line))
if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line);
continue;
case tokenid::hash_endif:
parse_endif();
if (!expect(tokenid::end_of_line))
if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line);
continue;
default:
@ -511,11 +522,18 @@ void reshadefx::preprocessor::parse_if()
level.pp_token = _token;
level.input_index = _current_input_index;
// Evaluate expression after updating 'pp_token', so that it points at the beginning # token
level.value = evaluate_expression();
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
level.skipping = parent_skipping || !level.value;
if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
// Evaluate expression after updating 'pp_token', so that it points at the beginning # token
level.value = evaluate_expression();
level.skipping = !level.value;
}
_if_stack.push_back(std::move(level));
}
@ -528,16 +546,23 @@ void reshadefx::preprocessor::parse_ifdef()
if (!expect(tokenid::identifier))
return;
level.value = is_defined(_token.literal_as_string);
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
level.skipping = parent_skipping || !level.value;
if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
level.value = is_defined(_token.literal_as_string);
level.skipping = !level.value;
_if_stack.push_back(std::move(level));
// Only add to used macro list if this #ifdef is active and the macro was not defined before
if (!parent_skipping)
// Only add to used macro list if this #ifdef is active and the macro was not defined before
if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined)
_used_macros.emplace(_token.literal_as_string);
}
_if_stack.push_back(std::move(level));
}
void reshadefx::preprocessor::parse_ifndef()
{
@ -548,16 +573,23 @@ void reshadefx::preprocessor::parse_ifndef()
if (!expect(tokenid::identifier))
return;
level.value = !is_defined(_token.literal_as_string);
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
level.skipping = parent_skipping || !level.value;
if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
level.value = !is_defined(_token.literal_as_string);
level.skipping = !level.value;
_if_stack.push_back(std::move(level));
// Only add to used macro list if this #ifndef is active and the macro was not defined before
if (!parent_skipping)
// Only add to used macro list if this #ifndef is active and the macro was not defined before
if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined)
_used_macros.emplace(_token.literal_as_string);
}
_if_stack.push_back(std::move(level));
}
void reshadefx::preprocessor::parse_elif()
{
@ -573,10 +605,19 @@ void reshadefx::preprocessor::parse_elif()
level.input_index = _current_input_index;
const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping;
const bool condition_result = evaluate_expression();
level.skipping = parent_skipping || level.value || !condition_result;
if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
const bool condition_result = evaluate_expression();
level.skipping = level.value || !condition_result;
if (!level.value) level.value = condition_result;
if (!level.value)
level.value = condition_result;
}
}
void reshadefx::preprocessor::parse_else()
{
@ -591,16 +632,25 @@ void reshadefx::preprocessor::parse_else()
level.input_index = _current_input_index;
const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping;
level.skipping = parent_skipping || level.value;
if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
level.skipping = parent_skipping || level.value;
if (!level.value) level.value = true;
if (!level.value)
level.value = true;
}
}
void reshadefx::preprocessor::parse_endif()
{
if (_if_stack.empty())
error(_token.location, "missing #if for #endif");
else
_if_stack.pop_back();
return error(_token.location, "missing #if for #endif");
_if_stack.pop_back();
}
void reshadefx::preprocessor::parse_error()
@ -927,8 +977,8 @@ bool reshadefx::preprocessor::evaluate_expression()
break;
if (left_associative ?
(precedence_lookup[op] > precedence_lookup[prev_op]) :
(precedence_lookup[op] >= precedence_lookup[prev_op]))
(s_precedence_lookup[op] > s_precedence_lookup[prev_op]) :
(s_precedence_lookup[op] >= s_precedence_lookup[prev_op]))
break;
stack_index--;
@ -1016,9 +1066,13 @@ bool reshadefx::preprocessor::evaluate_expression()
BINARY_OPERATION(-);
break;
case op_modulo:
if (stack[stack_index - 1] == 0)
return error(_token.location, "right operand of '%' is zero"), 0;
BINARY_OPERATION(%);
break;
case op_divide:
if (stack[stack_index - 1] == 0)
return error(_token.location, "division by zero"), 0;
BINARY_OPERATION(/);
break;
case op_multiply:
@ -1068,12 +1122,24 @@ bool reshadefx::preprocessor::evaluate_identifier_as_macro()
push(escape_string(file_stem.u8string()));
return true;
}
if (_token.literal_as_string == "__FILE_STEM_HASH__")
{
const std::filesystem::path file_stem = std::filesystem::u8path(_token.location.source).stem();
push(std::to_string(std::hash<std::string>()(file_stem.u8string()) & 0xFFFFFFFF));
return true;
}
if (_token.literal_as_string == "__FILE_NAME__")
{
const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename();
push(escape_string(file_name.u8string()));
return true;
}
if (_token.literal_as_string == "__FILE_NAME_HASH__")
{
const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename();
push(std::to_string(std::hash<std::string>()(file_name.u8string()) & 0xFFFFFFFF));
return true;
}
const auto it = _macros.find(_token.literal_as_string);
if (it == _macros.end())

View File

@ -13,25 +13,23 @@
#include <algorithm> // std::upper_bound, std::sort
#include <functional> // std::greater
enum class intrinsic_id : uint32_t
enum class intrinsic_id
{
#define IMPLEMENT_INTRINSIC_SPIRV(name, i, code) name##i,
#include "effect_symbol_table_intrinsics.inl"
};
struct intrinsic
struct intrinsic : reshadefx::function
{
intrinsic(const char *name, intrinsic_id id, const reshadefx::type &ret_type, std::initializer_list<reshadefx::type> arg_types) : id(id)
intrinsic(const char *name, intrinsic_id id, const reshadefx::type &ret_type, std::initializer_list<reshadefx::type> arg_types)
{
function.name = name;
function.return_type = ret_type;
function.parameter_list.reserve(arg_types.size());
function::return_type = ret_type;
function::id = static_cast<uint32_t>(id);
function::name = name;
function::parameter_list.reserve(arg_types.size());
for (const reshadefx::type &arg_type : arg_types)
function.parameter_list.push_back({ arg_type });
function::parameter_list.push_back({ arg_type });
}
intrinsic_id id;
reshadefx::function_info function;
};
#define void { reshadefx::type::t_void }
@ -130,48 +128,17 @@ static const intrinsic s_intrinsics[] =
#undef uint2
#undef uint3
#undef uint4
#undef float1
#undef float
#undef float2
#undef float3
#undef float4
#undef float2x2
#undef float3x3
#undef float4x4
#undef out_float
#undef out_float2
#undef out_float3
#undef out_float4
#undef sampler1d_int
#undef sampler2d_int
#undef sampler3d_int
#undef sampler1d_uint
#undef sampler2d_uint
#undef sampler3d_uint
#undef sampler1d_float4
#undef sampler2d_float4
#undef sampler3d_float4
#undef storage1d_int
#undef storage2d_int
#undef storage3d_int
#undef storage1d_uint
#undef storage2d_uint
#undef storage3d_uint
#undef storage1d_float4
#undef storage2d_float4
#undef storage3d_float4
#undef inout_storage1d_int
#undef inout_storage2d_int
#undef inout_storage3d_int
#undef inout_storage1d_uint
#undef inout_storage2d_uint
#undef inout_storage3d_uint
unsigned int reshadefx::type::rank(const type &src, const type &dst)
{
if (src.is_array() != dst.is_array() || (src.array_length != dst.array_length && src.array_length > 0 && dst.array_length > 0))
if (src.is_array() != dst.is_array() || (src.array_length != dst.array_length && src.is_bounded_array() && dst.is_bounded_array()))
return 0; // Arrays of different sizes are not compatible
if (src.is_struct() || dst.is_struct())
return src.definition == dst.definition ? 32 : 0; // Structs are only compatible if they are the same type
return src.struct_definition == dst.struct_definition ? 32 : 0; // Structs are only compatible if they are the same type
if (!src.is_numeric() || !dst.is_numeric())
return src.base == dst.base && src.rows == dst.rows && src.cols == dst.cols ? 32 : 0; // Numeric values are not compatible with other types
if (src.is_matrix() && (!dst.is_matrix() || src.rows != dst.rows || src.cols != dst.cols))
@ -181,7 +148,7 @@ unsigned int reshadefx::type::rank(const type &src, const type &dst)
// - Floating point has a higher rank than integer types
// - Integer to floating point promotion has a higher rank than floating point to integer conversion
// - Signed to unsigned integer conversion has a higher rank than unsigned to signed integer conversion
static const int ranks[7][7] = {
static const unsigned int ranks[7][7] = {
{ 5, 4, 4, 4, 4, 4, 4 }, // bool
{ 3, 5, 5, 2, 2, 4, 4 }, // min16int
{ 3, 5, 5, 2, 2, 4, 4 }, // int
@ -194,7 +161,7 @@ unsigned int reshadefx::type::rank(const type &src, const type &dst)
assert(src.base > 0 && src.base <= 7); // bool - float
assert(dst.base > 0 && dst.base <= 7);
const int rank = ranks[src.base - 1][dst.base - 1] << 2;
const unsigned int rank = ranks[src.base - 1][dst.base - 1] << 2;
if ((src.is_scalar() && dst.is_vector()))
return rank >> 1; // Scalar to vector promotion has a lower rank
@ -284,7 +251,7 @@ bool reshadefx::symbol_table::insert_symbol(const std::string &name, const symbo
{
// Extract scope name
scope.name = _current_scope.name.substr(0, pos += 2);
const auto previous_scope_name = _current_scope.name.substr(pos);
const std::string previous_scope_name = _current_scope.name.substr(pos);
// Insert symbol into this scope
insert_sorted(_symbol_stack[previous_scope_name + name], scoped_symbol { symbol, scope });
@ -335,7 +302,7 @@ reshadefx::scoped_symbol reshadefx::symbol_table::find_symbol(const std::string
return result;
}
static int compare_functions(const std::vector<reshadefx::expression> &arguments, const reshadefx::function_info *function1, const reshadefx::function_info *function2)
static int compare_functions(const std::vector<reshadefx::expression> &arguments, const reshadefx::function *function1, const reshadefx::function *function2)
{
const size_t num_arguments = arguments.size();
@ -388,7 +355,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
{
out_data.op = symbol_type::function;
const function_info *result = nullptr;
const function *result = nullptr;
unsigned int num_overloads = 0;
unsigned int overload_namespace = scope.namespace_level;
@ -405,7 +372,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
it->scope.namespace_level > scope.namespace_level || (it->scope.namespace_level == scope.namespace_level && it->scope.name != scope.name))
continue;
const function_info *const function = it->function;
const function *const function = it->function;
if (function == nullptr)
continue;
@ -425,7 +392,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
continue;
}
}
else if (arguments.size() != function->parameter_list.size())
else if (arguments.size() > function->parameter_list.size() || (arguments.size() < function->parameter_list.size() && !function->parameter_list[arguments.size()].has_default_value))
{
continue;
}
@ -453,18 +420,18 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
{
for (const intrinsic &intrinsic : s_intrinsics)
{
if (intrinsic.function.name != name || intrinsic.function.parameter_list.size() != arguments.size())
if (intrinsic.name != name || intrinsic.parameter_list.size() != arguments.size())
continue;
// A new possibly-matching intrinsic function was found, compare it against the current result
const int comparison = compare_functions(arguments, &intrinsic.function, result);
const int comparison = compare_functions(arguments, &intrinsic, result);
if (comparison < 0) // The new function is a better match
{
out_data.op = symbol_type::intrinsic;
out_data.id = static_cast<uint32_t>(intrinsic.id);
out_data.type = intrinsic.function.return_type;
out_data.function = &intrinsic.function;
out_data.id = intrinsic.id;
out_data.type = intrinsic.return_type;
out_data.function = &intrinsic;
result = out_data.function;
num_overloads = 1;
}

File diff suppressed because it is too large Load Diff