printf: extract clovers printf impl

Also make the code cleaner and simplier.

Signed-off-by: Karol Herbst <kherbst@redhat.com>
Acked-by: Jesse Natalie <jenatali@microsoft.com>
Reviewed-by: Jason Ekstrand <jason.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17334>
This commit is contained in:
Karol Herbst
2022-04-16 10:48:08 +02:00
committed by Marge Bot
parent 160aa603f5
commit aa82808645
7 changed files with 176 additions and 134 deletions

View File

@@ -39,6 +39,7 @@
#include "util/compiler.h"
#include "util/enum_operators.h"
#include "util/macros.h"
#include "util/u_printf.h"
#include "util/format/u_format.h"
#include "compiler/nir_types.h"
#include "compiler/shader_enums.h"
@@ -3157,13 +3158,6 @@ typedef struct {
uint8_t bit_size;
} nir_parameter;
typedef struct nir_printf_info {
unsigned num_args;
unsigned *arg_sizes;
unsigned string_size;
char *strings;
} nir_printf_info;
typedef struct nir_function {
struct exec_node node;
@@ -3732,7 +3726,7 @@ typedef struct nir_shader {
struct nir_xfb_info *xfb_info;
unsigned printf_info_count;
nir_printf_info *printf_info;
u_printf_info *printf_info;
} nir_shader;
#define nir_foreach_function(func, shader) \

View File

@@ -726,7 +726,7 @@ vtn_handle_opencl_vstore_half_r(struct vtn_builder *b, enum OpenCLstd_Entrypoint
}
static unsigned
vtn_add_printf_string(struct vtn_builder *b, uint32_t id, nir_printf_info *info)
vtn_add_printf_string(struct vtn_builder *b, uint32_t id, u_printf_info *info)
{
nir_deref_instr *deref = vtn_nir_deref(b, id);
@@ -783,8 +783,8 @@ handle_printf(struct vtn_builder *b, uint32_t opcode,
unsigned info_idx = b->shader->printf_info_count;
b->shader->printf_info = reralloc(b->shader, b->shader->printf_info,
nir_printf_info, info_idx);
nir_printf_info *info = &b->shader->printf_info[info_idx - 1];
u_printf_info, info_idx);
u_printf_info *info = &b->shader->printf_info[info_idx - 1];
info->strings = NULL;
info->string_size = 0;

View File

@@ -57,7 +57,7 @@ namespace clover {
struct printf_info {
std::vector<uint32_t> arg_sizes;
std::vector<uint8_t> strings;
std::vector<char> strings;
};
struct arg_info {

View File

@@ -40,136 +40,28 @@ namespace {
const std::string clc_printf_whitelist = "%0123456789-+ #.AacdeEfFgGhilopsuvxX";
void
print_formatted(const std::vector<binary::printf_info> &formatters,
print_formatted(std::vector<binary::printf_info> &formatters,
bool _strings_in_buffer,
const std::vector<char> &buffer) {
static std::atomic<unsigned> warn_count;
if (buffer.empty() && !warn_count++)
std::cerr << "Printf used but no printf occurred - may cause perfomance issue." << std::endl;
std::cerr << "Printf used but no printf occurred - may cause perfomance issue." << std::endl;
for (size_t buf_pos = 0; buf_pos < buffer.size(); ) {
cl_uint fmt_idx = *(cl_uint*)&buffer[buf_pos];
assert(fmt_idx > 0);
binary::printf_info fmt = formatters[fmt_idx-1];
std::vector<u_printf_info> infos;
for (auto &f : formatters) {
u_printf_info info;
std::string format = (char *)fmt.strings.data();
buf_pos += sizeof(cl_uint);
info.num_args = f.arg_sizes.size();
info.arg_sizes = f.arg_sizes.data();
info.string_size = f.strings.size();
info.strings = f.strings.data();
if (fmt.arg_sizes.empty()) {
printf("%s", format.c_str());
} else {
size_t fmt_last_pos = 0;
size_t fmt_pos = 0;
for (int arg_size : fmt.arg_sizes) {
const size_t spec_pos = util_printf_next_spec_pos(format.c_str(), fmt_pos);
const size_t cur_tok = format.rfind('%', spec_pos);
const size_t next_spec = util_printf_next_spec_pos(format.c_str(), spec_pos);
const size_t next_tok = next_spec == std::string::npos ? std::string::npos :
format.rfind('%', next_spec);
size_t vec_pos = format.find_first_of("v", cur_tok + 1);
size_t mod_pos = format.find_first_of("hl", cur_tok + 1);
// print the part before the format token
if (cur_tok != fmt_last_pos) {
std::string s = format.substr(fmt_last_pos,
cur_tok - fmt_last_pos);
printf("%s", s.c_str());
}
std::string print_str;
print_str = format.substr(cur_tok, spec_pos + 1 - cur_tok);
/* Never pass a 'n' spec to the host printf */
bool valid_str = print_str.find_first_not_of(clc_printf_whitelist) ==
std::string::npos;
// print the formated part
if (spec_pos != std::string::npos && valid_str) {
bool is_vector = vec_pos != std::string::npos &&
vec_pos + 1 < spec_pos;
bool is_string = format[spec_pos] == 's';
bool is_float = std::string("fFeEgGaA")
.find(format[spec_pos]) != std::string::npos;
if (is_string) {
if (_strings_in_buffer)
printf(print_str.c_str(), &buffer[buf_pos]);
else {
uint64_t idx;
memcpy(&idx, &buffer[buf_pos], 8);
printf(print_str.c_str(), &fmt.strings[idx]);
}
} else {
int component_count = 1;
if (is_vector) {
size_t l = std::min(mod_pos, spec_pos) - vec_pos - 1;
std::string s = format.substr(vec_pos + 1, l);
component_count = std::stoi(s);
if (mod_pos != std::string::npos) {
// CL C has hl specifier for 32-bit vectors, C doesn't have it
// just remove it.
std::string mod = format.substr(mod_pos, 2);
if (mod == "hl")
mod_pos = std::string::npos;
}
print_str.erase(vec_pos - cur_tok, std::min(mod_pos, spec_pos) - vec_pos);
print_str.push_back(',');
}
//in fact vec3 are vec4
int men_components =
component_count == 3 ? 4 : component_count;
size_t elmt_size = arg_size / men_components;
for (int i = 0; i < component_count; i++) {
size_t elmt_buf_pos = buf_pos + i * elmt_size;
if (is_vector && i + 1 == component_count)
print_str.pop_back();
if (is_float) {
switch (elmt_size) {
case 2:
cl_half h;
std::memcpy(&h, &buffer[elmt_buf_pos], elmt_size);
printf(print_str.c_str(), h);
break;
case 4:
cl_float f;
std::memcpy(&f, &buffer[elmt_buf_pos], elmt_size);
printf(print_str.c_str(), f);
break;
default:
cl_double d;
std::memcpy(&d, &buffer[elmt_buf_pos], elmt_size);
printf(print_str.c_str(), d);
}
} else {
cl_long l = 0;
std::memcpy(&l, &buffer[elmt_buf_pos], elmt_size);
printf(print_str.c_str(), l);
}
}
}
// print the remaining
if (next_tok != spec_pos) {
std::string s = format.substr(spec_pos + 1,
next_tok - spec_pos - 1);
printf("%s", s.c_str());
}
}
fmt_pos = spec_pos;
fmt_last_pos = next_tok;
buf_pos += arg_size;
buf_pos = ALIGN(buf_pos, 4);
}
}
infos.push_back(info);
}
u_printf(stdout, buffer.data(), buffer.size(), infos.data(), infos.size());
}
}

View File

@@ -588,7 +588,7 @@ binary clover::nir::spirv_to_nir(const binary &mod, const device &dev,
void *mem_ctx = ralloc_context(NULL);
unsigned printf_info_count = nir->printf_info_count;
nir_printf_info *printf_infos = nir->printf_info;
u_printf_info *printf_infos = nir->printf_info;
ralloc_steal(mem_ctx, printf_infos);

View File

@@ -23,9 +23,13 @@
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "macros.h"
#include "strndup.h"
#include "u_math.h"
#include "u_printf.h"
/* Some versions of MinGW are missing _vscprintf's declaration, although they
@@ -42,6 +46,14 @@ _CRTIMP int _vscprintf(const char *format, va_list argptr);
#endif
#endif
static const char*
util_printf_prev_tok(const char *str)
{
while (*str != '%')
str--;
return str;
}
size_t util_printf_next_spec_pos(const char *str, size_t pos)
{
if (str == NULL)
@@ -94,3 +106,137 @@ size_t u_printf_length(const char *fmt, va_list untouched_args)
return size;
}
void u_printf(FILE *out, const char *buffer, size_t buffer_size,
const u_printf_info *info, unsigned info_size)
{
for (size_t buf_pos = 0; buf_pos < buffer_size;) {
uint32_t fmt_idx = *(uint32_t*)&buffer[buf_pos];
/* the idx is 1 based */
assert(fmt_idx > 0);
fmt_idx -= 1;
/* The API allows more arguments than the format uses */
if (fmt_idx >= info_size)
return;
const u_printf_info *fmt = &info[fmt_idx];
const char *format = fmt->strings;
buf_pos += sizeof(fmt_idx);
if (!fmt->num_args) {
fprintf(out, "%s", format);
continue;
}
for (int i = 0; i < fmt->num_args; i++) {
int arg_size = fmt->arg_sizes[i];
size_t spec_pos = util_printf_next_spec_pos(format, 0);
if (spec_pos == -1) {
fprintf(out, "%s", format);
continue;
}
const char *token = util_printf_prev_tok(&format[spec_pos]);
const char *next_format = &format[spec_pos + 1];
/* print the part before the format token */
if (token != format)
fwrite(format, token - format, 1, out);
char *print_str = strndup(token, next_format - token);
/* rebase spec_pos so we can use it with print_str */
spec_pos += format - token;
/* print the formated part */
if (print_str[spec_pos] == 's') {
uint64_t idx;
memcpy(&idx, &buffer[buf_pos], 8);
fprintf(out, print_str, &fmt->strings[idx]);
/* Never pass a 'n' spec to the host printf */
} else if (print_str[spec_pos] != 'n') {
char *vec_pos = strchr(print_str, 'v');
char *mod_pos = strpbrk(print_str, "hl");
int component_count = 1;
if (vec_pos != NULL) {
/* non vector part of the format */
size_t base = mod_pos ? mod_pos - print_str : spec_pos;
size_t l = base - (vec_pos - print_str) - 1;
char *vec = strndup(&vec_pos[1], l);
component_count = atoi(vec);
free(vec);
/* remove the vector and precision stuff */
memmove(&print_str[vec_pos - print_str], &print_str[spec_pos], 2);
}
/* in fact vec3 are vec4 */
int men_components = component_count == 3 ? 4 : component_count;
size_t elmt_size = arg_size / men_components;
bool is_float = strpbrk(print_str, "fFeEgGaA") != NULL;
for (int i = 0; i < component_count; i++) {
size_t elmt_buf_pos = buf_pos + i * elmt_size;
switch (elmt_size) {
case 1: {
uint8_t v;
memcpy(&v, &buffer[elmt_buf_pos], elmt_size);
fprintf(out, print_str, v);
break;
}
case 2: {
uint16_t v;
memcpy(&v, &buffer[elmt_buf_pos], elmt_size);
fprintf(out, print_str, v);
break;
}
case 4: {
if (is_float) {
float v;
memcpy(&v, &buffer[elmt_buf_pos], elmt_size);
fprintf(out, print_str, v);
} else {
uint32_t v;
memcpy(&v, &buffer[elmt_buf_pos], elmt_size);
fprintf(out, print_str, v);
}
break;
}
case 8: {
if (is_float) {
double v;
memcpy(&v, &buffer[elmt_buf_pos], elmt_size);
fprintf(out, print_str, v);
} else {
uint64_t v;
memcpy(&v, &buffer[elmt_buf_pos], elmt_size);
fprintf(out, print_str, v);
}
break;
}
default:
assert(false);
break;
}
if (i < component_count - 1)
fprintf(out, ",");
}
}
/* rebase format */
format = next_format;
free(print_str);
buf_pos += arg_size;
buf_pos = ALIGN(buf_pos, 4);
}
/* print remaining */
fprintf(out, "%s", format);
}
}

View File

@@ -29,6 +29,13 @@
extern "C" {
#endif
typedef struct u_printf_info {
unsigned num_args;
unsigned *arg_sizes;
unsigned string_size;
char *strings;
} u_printf_info;
/* find next valid printf specifier in a C string wrapper */
size_t util_printf_next_spec_pos(const char *str, size_t pos);
@@ -39,6 +46,9 @@ size_t util_printf_next_spec_pos(const char *str, size_t pos);
*/
size_t u_printf_length(const char *fmt, va_list untouched_args);
void u_printf(FILE *out, const char *buffer, size_t buffer_size,
const u_printf_info*, unsigned info_size);
#ifdef __cplusplus
}
#endif