mirror of OpenBSD xenocara tree github.com/openbsd/xenocara
openbsd
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at jcs 307 lines 11 kB view raw
1/* 2 * Copyright © 2020 Microsoft Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "nir.h" 25#include "nir_builder.h" 26#include "nir_builder_opcodes.h" 27 28#include "util/u_math.h" 29#include "util/u_printf.h" 30 31static bool 32lower_printf_intrin(nir_builder *b, nir_intrinsic_instr *prntf, void *_options) 33{ 34 const nir_lower_printf_options *options = _options; 35 if (prntf->intrinsic != nir_intrinsic_printf && 36 prntf->intrinsic != nir_intrinsic_printf_abort) 37 return false; 38 39 b->cursor = nir_before_instr(&prntf->instr); 40 41 const unsigned ptr_bit_size = 42 options->ptr_bit_size != 0 ? options->ptr_bit_size : nir_get_ptr_bitsize(b->shader); 43 44 nir_def *buffer_addr = nir_load_printf_buffer_address(b, ptr_bit_size); 45 46 /* For aborts, just write a nonzero value to the aborted? flag. The printf 47 * buffer layout looks like: 48 * 49 * uint32_t size; 50 * uint32_t aborted; 51 * uint32_t data[]; 52 */ 53 if (prntf->intrinsic == nir_intrinsic_printf_abort) { 54 nir_store_global(b, nir_iadd_imm(b, buffer_addr, 4), 4, nir_imm_int(b, 1), 55 nir_component_mask(1)); 56 57 /* Halt is a jump instruction so can only appear at the end of a block. 58 * The abort might be in the middle of a block. So, wrap the halt and let 59 * control flow optimization clean up after us. 60 */ 61 nir_push_if(b, nir_imm_true(b)); 62 { 63 nir_jump(b, nir_jump_halt); 64 } 65 nir_pop_if(b, NULL); 66 67 nir_instr_remove(&prntf->instr); 68 return true; 69 } 70 71 nir_def *fmt_str_id = prntf->src[0].ssa; 72 if (options->use_printf_base_identifier) { 73 fmt_str_id = nir_iadd(b, 74 nir_load_printf_base_identifier(b), 75 fmt_str_id); 76 } else if (options->hash_format_strings) { 77 /* Rather than store the index of the format string, instead store the 78 * hash of the format string itself. This is invariant across shaders 79 * which may be more convenient. 80 */ 81 unsigned idx = nir_src_as_uint(prntf->src[0]) - 1; 82 assert(idx < b->shader->printf_info_count && "must be in-bounds"); 83 84 uint32_t hash = u_printf_hash(&b->shader->printf_info[idx]); 85 fmt_str_id = nir_imm_int(b, hash); 86 } 87 88 nir_deref_instr *args = nir_src_as_deref(prntf->src[1]); 89 assert(args->deref_type == nir_deref_type_var); 90 91 /* Atomic add a buffer size counter to determine where to write. If 92 * overflowed, return -1, otherwise, store the arguments and return 0. 93 */ 94 nir_deref_instr *buffer = 95 nir_build_deref_cast(b, buffer_addr, nir_var_mem_global, 96 glsl_array_type(glsl_uint8_t_type(), 0, 4), 0); 97 98 /* Align the struct size to 4 */ 99 assert(glsl_type_is_struct_or_ifc(args->type)); 100 int args_size = align(glsl_get_cl_size(args->type), 4); 101 assert(fmt_str_id->bit_size == 32); 102 int fmt_str_id_size = 4; 103 104 /* Increment the counter at the beginning of the buffer */ 105 const unsigned counter_size = 4; 106 nir_deref_instr *counter = nir_build_deref_array_imm(b, buffer, 0); 107 counter = nir_build_deref_cast(b, &counter->def, 108 nir_var_mem_global, 109 glsl_uint_type(), 0); 110 counter->cast.align_mul = 4; 111 nir_def *offset = 112 nir_deref_atomic(b, 32, &counter->def, 113 nir_imm_int(b, fmt_str_id_size + args_size), 114 .atomic_op = nir_atomic_op_iadd); 115 116 /* Check if we're still in-bounds */ 117 nir_def *buffer_size; 118 if (options->max_buffer_size) { 119 buffer_size = nir_imm_int(b, options->max_buffer_size); 120 } else { 121 buffer_size = nir_load_printf_buffer_size(b); 122 } 123 124 unsigned this_printf_size = args_size + fmt_str_id_size + counter_size; 125 nir_push_if(b, nir_ult(b, offset, nir_iadd_imm(b, buffer_size, -this_printf_size))); 126 127 nir_def *printf_succ_val = nir_imm_int(b, 0); 128 129 offset = nir_u2uN(b, offset, ptr_bit_size); 130 131 /* Write the format string ID */ 132 nir_deref_instr *fmt_str_id_deref = nir_build_deref_array(b, buffer, offset); 133 fmt_str_id_deref = nir_build_deref_cast(b, &fmt_str_id_deref->def, 134 nir_var_mem_global, 135 glsl_uint_type(), 0); 136 fmt_str_id_deref->cast.align_mul = 4; 137 nir_store_deref(b, fmt_str_id_deref, fmt_str_id, ~0); 138 139 /* Write the format args */ 140 for (unsigned i = 0; i < glsl_get_length(args->type); ++i) { 141 nir_deref_instr *arg_deref = nir_build_deref_struct(b, args, i); 142 nir_def *arg = nir_load_deref(b, arg_deref); 143 const struct glsl_type *arg_type = arg_deref->type; 144 145 unsigned field_offset = glsl_get_struct_field_offset(args->type, i); 146 nir_def *arg_offset = 147 nir_iadd_imm(b, offset, fmt_str_id_size + field_offset); 148 nir_deref_instr *dst_arg_deref = 149 nir_build_deref_array(b, buffer, arg_offset); 150 dst_arg_deref = nir_build_deref_cast(b, &dst_arg_deref->def, 151 nir_var_mem_global, arg_type, 0); 152 assert(field_offset % 4 == 0); 153 dst_arg_deref->cast.align_mul = 4; 154 nir_store_deref(b, dst_arg_deref, arg, ~0); 155 } 156 157 nir_push_else(b, NULL); 158 nir_def *printf_fail_val = nir_imm_int(b, -1); 159 nir_pop_if(b, NULL); 160 161 nir_def *ret_val = nir_if_phi(b, printf_succ_val, printf_fail_val); 162 nir_def_replace(&prntf->def, ret_val); 163 164 return true; 165} 166 167bool 168nir_lower_printf(nir_shader *nir, const nir_lower_printf_options *options) 169{ 170 return nir_shader_intrinsics_pass(nir, lower_printf_intrin, 171 nir_metadata_none, 172 (void *)options); 173} 174 175struct buffer_opts { 176 uint64_t address; 177 uint32_t size; 178}; 179 180static bool 181lower_printf_buffer(nir_builder *b, nir_intrinsic_instr *intr, void *_options) 182{ 183 const struct buffer_opts *options = _options; 184 185 uint64_t value = 0; 186 if (intr->intrinsic == nir_intrinsic_load_printf_buffer_address) 187 value = options->address; 188 else if (intr->intrinsic == nir_intrinsic_load_printf_buffer_size) 189 value = options->size; 190 191 if (value == 0) 192 return false; 193 194 b->cursor = nir_before_instr(&intr->instr); 195 nir_def_replace(&intr->def, nir_imm_intN_t(b, value, intr->def.bit_size)); 196 return true; 197} 198 199bool 200nir_lower_printf_buffer(nir_shader *nir, uint64_t address, uint32_t size) 201{ 202 struct buffer_opts opts = { .address = address, .size = size }; 203 204 return nir_shader_intrinsics_pass(nir, lower_printf_buffer, 205 nir_metadata_control_flow, &opts); 206} 207 208void 209nir_printf_fmt(nir_builder *b, 210 bool use_printf_base_identifier, 211 unsigned ptr_bit_size, 212 const char *fmt, ...) 213{ 214 b->shader->printf_info_count++; 215 b->shader->printf_info = reralloc(b->shader, 216 b->shader->printf_info, 217 u_printf_info, 218 b->shader->printf_info_count); 219 220 u_printf_info *info = 221 &b->shader->printf_info[b->shader->printf_info_count - 1]; 222 223 *info = (u_printf_info) { 224 .strings = ralloc_strdup(b->shader, fmt), 225 .string_size = strlen(fmt) + 1, 226 }; 227 228 va_list ap; 229 size_t pos = 0; 230 size_t args_size = 0; 231 232 va_start(ap, fmt); 233 while ((pos = util_printf_next_spec_pos(fmt, pos)) != -1) { 234 unsigned arg_size; 235 switch (fmt[pos]) { 236 case 'c': arg_size = 1; break; 237 case 'd': arg_size = 4; break; 238 case 'e': arg_size = 4; break; 239 case 'E': arg_size = 4; break; 240 case 'f': arg_size = 4; break; 241 case 'F': arg_size = 4; break; 242 case 'G': arg_size = 4; break; 243 case 'a': arg_size = 4; break; 244 case 'A': arg_size = 4; break; 245 case 'i': arg_size = 4; break; 246 case 'u': arg_size = 4; break; 247 case 'x': arg_size = 4; break; 248 case 'X': arg_size = 4; break; 249 case 'p': arg_size = 8; break; 250 default: unreachable("invalid"); 251 } 252 253 ASSERTED nir_def *def = va_arg(ap, nir_def*); 254 assert(def->bit_size / 8 == arg_size); 255 256 info->num_args++; 257 info->arg_sizes = reralloc(b->shader, 258 info->arg_sizes, 259 unsigned, info->num_args); 260 info->arg_sizes[info->num_args - 1] = arg_size; 261 262 args_size += arg_size; 263 } 264 va_end(ap); 265 266 nir_def *buffer_addr = 267 nir_load_printf_buffer_address( 268 b, ptr_bit_size ? ptr_bit_size : nir_get_ptr_bitsize(b->shader)); 269 nir_def *buffer_offset = 270 nir_global_atomic(b, 32, buffer_addr, 271 nir_imm_int(b, args_size + sizeof(uint32_t)), 272 .atomic_op = nir_atomic_op_iadd); 273 274 uint32_t total_size = sizeof(uint32_t); /* identifier */ 275 for (unsigned a = 0; a < info->num_args; a++) 276 total_size += info->arg_sizes[a]; 277 278 nir_push_if(b, nir_ilt(b, nir_iadd_imm(b, buffer_offset, total_size), 279 nir_load_printf_buffer_size(b))); 280 { 281 /* Identifier */ 282 nir_def *identifier = 283 use_printf_base_identifier ? 284 nir_iadd_imm(b, 285 nir_load_printf_base_identifier(b), 286 b->shader->printf_info_count) : 287 nir_imm_int(b, b->shader->printf_info_count); 288 289 nir_def *store_addr = 290 nir_iadd(b, buffer_addr, nir_u2uN(b, buffer_offset, buffer_addr->bit_size)); 291 nir_store_global(b, store_addr, 4, identifier, 0x1); 292 293 /* Arguments */ 294 va_start(ap, fmt); 295 unsigned store_offset = sizeof(uint32_t); 296 for (unsigned a = 0; a < info->num_args; a++) { 297 nir_def *def = va_arg(ap, nir_def*); 298 299 nir_store_global(b, nir_iadd_imm(b, store_addr, store_offset), 300 4, def, 0x1); 301 302 store_offset += info->arg_sizes[a]; 303 } 304 va_end(ap); 305 } 306 nir_pop_if(b, NULL); 307}