diff --git a/src/microsoft/compiler/dxil_buffer.c b/src/microsoft/compiler/dxil_buffer.c new file mode 100644 index 00000000000..495d668e0fd --- /dev/null +++ b/src/microsoft/compiler/dxil_buffer.c @@ -0,0 +1,104 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#include "dxil_buffer.h" +#include + +void +dxil_buffer_init(struct dxil_buffer *b, unsigned abbrev_width) +{ + blob_init(&b->blob); + b->buf = 0; + b->buf_bits = 0; + + b->abbrev_width = abbrev_width; +} + +void +dxil_buffer_finish(struct dxil_buffer *b) +{ + blob_finish(&b->blob); +} + +static bool +flush_dword(struct dxil_buffer *b) +{ + assert(b->buf_bits >= 32 && b->buf_bits < 64); + + uint32_t lower_bits = b->buf & UINT32_MAX; + if (!blob_write_bytes(&b->blob, &lower_bits, sizeof(lower_bits))) + return false; + + b->buf >>= 32; + b->buf_bits -= 32; + + return true; +} + +bool +dxil_buffer_emit_bits(struct dxil_buffer *b, uint32_t data, unsigned width) +{ + assert(b->buf_bits < 32); + assert(width > 0 && width <= 32); + assert((data & ~((UINT64_C(1) << width) - 1)) == 0); + + b->buf |= ((uint64_t)data) << b->buf_bits; + b->buf_bits += width; + + if (b->buf_bits >= 32) + return flush_dword(b); + + return true; +} + +bool +dxil_buffer_emit_vbr_bits(struct dxil_buffer *b, uint64_t data, + unsigned width) +{ + assert(width > 1 && width <= 32); + + uint32_t tag = UINT32_C(1) << (width - 1); + uint32_t max = tag - 1; + while (data > max) { + uint32_t value = (data & max) | tag; + data >>= width - 1; + + if (!dxil_buffer_emit_bits(b, value, width)) + return false; + } + + return dxil_buffer_emit_bits(b, data, width); +} + +bool +dxil_buffer_align(struct dxil_buffer *b) +{ + assert(b->buf_bits < 32); + + if (b->buf_bits) { + b->buf_bits = 32; + return flush_dword(b); + } + + return true; +} diff --git a/src/microsoft/compiler/dxil_buffer.h b/src/microsoft/compiler/dxil_buffer.h new file mode 100644 index 00000000000..4f0cc60b238 --- /dev/null +++ b/src/microsoft/compiler/dxil_buffer.h @@ -0,0 +1,60 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#ifndef DXIL_BUFFER_H +#define DXIL_BUFFER_H + +#include "util/blob.h" + +struct dxil_buffer { + struct blob blob; + uint64_t buf; + unsigned buf_bits; + + unsigned abbrev_width; +}; + +void +dxil_buffer_init(struct dxil_buffer *b, unsigned abbrev_width); + +void +dxil_buffer_finish(struct dxil_buffer *b); + +bool +dxil_buffer_emit_bits(struct dxil_buffer *b, uint32_t data, unsigned width); + +bool +dxil_buffer_emit_vbr_bits(struct dxil_buffer *b, uint64_t data, + unsigned width); + +bool +dxil_buffer_align(struct dxil_buffer *b); + +static bool +dxil_buffer_emit_abbrev_id(struct dxil_buffer *b, uint32_t id) +{ + return dxil_buffer_emit_bits(b, id, b->abbrev_width); +} + + +#endif diff --git a/src/microsoft/compiler/dxil_buffer_test.c b/src/microsoft/compiler/dxil_buffer_test.c new file mode 100644 index 00000000000..9c5b571cbf2 --- /dev/null +++ b/src/microsoft/compiler/dxil_buffer_test.c @@ -0,0 +1,129 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#include "dxil_buffer.h" +#include +#include + +static void +init() +{ + struct dxil_buffer buf; + dxil_buffer_init(&buf, 2); + assert(!buf.buf); + assert(!buf.buf_bits); +} + +static void +assert_blob_data(const struct dxil_buffer *m, const uint8_t *data, + size_t len) +{ + if (m->blob.size != len) { + fprintf(stderr, "blob-size mismatch, expected %zd, got %zd", + len, m->blob.size); + abort(); + } + + for (size_t i = 0; i < len; ++i) { + if (m->blob.data[i] != data[i]) { + fprintf(stderr, "blob-data mismatch at index %zd, " + "expected 0x%02x, got 0x%02x", i, + data[i], m->blob.data[i]); + abort(); + } + } +} + +#define ASSERT_BLOB_DATA(m, data) \ + assert_blob_data(m, data, sizeof(data)) + +static void +align() +{ + struct dxil_buffer buf; + dxil_buffer_init(&buf, 2); + assert_blob_data(&buf, NULL, 0); + + dxil_buffer_init(&buf, 2); + dxil_buffer_emit_bits(&buf, 0xbeef, 16); + dxil_buffer_align(&buf); + assert(!buf.buf); + assert(!buf.buf_bits); + uint8_t expected0[] = { 0xef, 0xbe, 0x00, 0x00 }; + ASSERT_BLOB_DATA(&buf, expected0); + dxil_buffer_align(&buf); + ASSERT_BLOB_DATA(&buf, expected0); +} + +static void +emit_bits() +{ + struct dxil_buffer buf; + dxil_buffer_init(&buf, 2); + dxil_buffer_emit_bits(&buf, 0xbeef, 16); + dxil_buffer_align(&buf); + assert(!buf.buf); + assert(!buf.buf_bits); + uint8_t expected0[] = { 0xef, 0xbe, 0x00, 0x00 }; + ASSERT_BLOB_DATA(&buf, expected0); + + dxil_buffer_init(&buf, 2); + dxil_buffer_emit_bits(&buf, 0xdead, 16); + dxil_buffer_emit_bits(&buf, 0xbeef, 16); + assert(!buf.buf); + assert(!buf.buf_bits); + uint8_t expected1[] = { 0xad, 0xde, 0xef, 0xbe }; + ASSERT_BLOB_DATA(&buf, expected1); + + dxil_buffer_init(&buf, 2); + dxil_buffer_emit_bits(&buf, 0x1111111, 28); + dxil_buffer_emit_bits(&buf, 0x22222222, 32); + dxil_buffer_align(&buf); + uint8_t expected2[] = { 0x11, 0x11, 0x11, 0x21, 0x22, 0x22, 0x22, 0x02 }; + ASSERT_BLOB_DATA(&buf, expected2); +} + +static void +emit_vbr_bits() +{ + struct dxil_buffer buf; + dxil_buffer_init(&buf, 2); + dxil_buffer_emit_vbr_bits(&buf, 0x1a, 8); + dxil_buffer_emit_vbr_bits(&buf, 0x1a, 6); + dxil_buffer_emit_vbr_bits(&buf, 0x00, 2); + dxil_buffer_emit_vbr_bits(&buf, 0x0a, 4); + dxil_buffer_emit_vbr_bits(&buf, 0x04, 2); + dxil_buffer_emit_vbr_bits(&buf, 0x00, 2); + uint8_t expected[] = { 0x1a, 0x1a, 0x1a, 0x1a }; + ASSERT_BLOB_DATA(&buf, expected); +} + +int +main() +{ + init(); + align(); + emit_bits(); + emit_vbr_bits(); + return 0; +} diff --git a/src/microsoft/compiler/dxil_container.c b/src/microsoft/compiler/dxil_container.c new file mode 100644 index 00000000000..94a1d49da41 --- /dev/null +++ b/src/microsoft/compiler/dxil_container.c @@ -0,0 +1,353 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#include "dxil_container.h" +#include "dxil_module.h" + +#include "util/u_debug.h" + +#include + +const uint32_t DXIL_DXBC = DXIL_FOURCC('D', 'X', 'B', 'C'); + +void +dxil_container_init(struct dxil_container *c) +{ + blob_init(&c->parts); + c->num_parts = 0; +} + +void +dxil_container_finish(struct dxil_container *c) +{ + blob_finish(&c->parts); +} + +static bool +add_part_header(struct dxil_container *c, + enum dxil_part_fourcc fourcc, + uint32_t part_size) +{ + assert(c->parts.size < UINT_MAX); + unsigned offset = (unsigned)c->parts.size; + if (!blob_write_bytes(&c->parts, &fourcc, sizeof(fourcc)) || + !blob_write_bytes(&c->parts, &part_size, sizeof(part_size))) + return false; + + assert(c->num_parts < DXIL_MAX_PARTS); + c->part_offsets[c->num_parts++] = offset; + return true; +} + +static bool +add_part(struct dxil_container *c, + enum dxil_part_fourcc fourcc, + const void *part_data, uint32_t part_size) +{ + return add_part_header(c, fourcc, part_size) && + blob_write_bytes(&c->parts, part_data, part_size); +} + +bool +dxil_container_add_features(struct dxil_container *c, + const struct dxil_features *features) +{ + union { + struct dxil_features flags; + uint64_t bits; + } u = { .flags = *features }; + return add_part(c, DXIL_SFI0, &u.bits, sizeof(u.bits)); +} + +typedef struct { + struct { + const char *name; + uint32_t offset; + } entries[DXIL_SHADER_MAX_IO_ROWS]; + uint32_t num_entries; +} name_offset_cache_t; + +static uint32_t +get_semantic_name_offset(name_offset_cache_t *cache, const char *name, + struct _mesa_string_buffer *buf, uint32_t buf_offset) +{ + /* consider replacing this with a binary search using rb_tree */ + for (unsigned i = 0; i < cache->num_entries; ++i) { + if (!strcmp(name, cache->entries[i].name)) + return cache->entries[i].offset; + } + + uint32_t offset = buf->length + buf_offset; + cache->entries[cache->num_entries].name = name; + cache->entries[cache->num_entries].offset = offset; + ++cache->num_entries; + _mesa_string_buffer_append_len(buf, name, strlen(name) + 1); + + return offset; +} + +static uint32_t +collect_semantic_names(unsigned num_records, + struct dxil_signature_record *io_data, + struct _mesa_string_buffer *buf, + uint32_t buf_offset) +{ + name_offset_cache_t cache; + cache.num_entries = 0; + + for (unsigned i = 0; i < num_records; ++i) { + struct dxil_signature_record *io = &io_data[i]; + uint32_t offset = get_semantic_name_offset(&cache, io->name, buf, buf_offset); + for (unsigned j = 0; j < io->num_elements; ++j) + io->elements[j].semantic_name_offset = offset; + } + return buf_offset + buf->length; +} + +bool +dxil_container_add_io_signature(struct dxil_container *c, + enum dxil_part_fourcc part, + unsigned num_records, + struct dxil_signature_record *io_data) +{ + struct { + uint32_t param_count; + uint32_t param_offset; + } header; + header.param_count = 0; + uint32_t fixed_size = sizeof(header); + header.param_offset = fixed_size; + + bool retval = true; + + for (unsigned i = 0; i < num_records; ++i) { + /* TODO: + * - Here we need to check whether the value is actually part of the + * signature */ + fixed_size += sizeof(struct dxil_signature_element) * io_data[i].num_elements; + header.param_count += io_data[i].num_elements; + } + + struct _mesa_string_buffer *names = + _mesa_string_buffer_create(NULL, 1024); + + uint32_t last_offset = collect_semantic_names(num_records, io_data, + names, fixed_size); + + + if (!add_part_header(c, part, last_offset) || + !blob_write_bytes(&c->parts, &header, sizeof(header))) { + retval = false; + goto cleanup; + } + + /* write all parts */ + for (unsigned i = 0; i < num_records; ++i) + for (unsigned j = 0; j < io_data[i].num_elements; ++j) { + if (!blob_write_bytes(&c->parts, &io_data[i].elements[j], + sizeof(io_data[i].elements[j]))) { + retval = false; + goto cleanup; + } + } + + /* write all names */ + + if (!blob_write_bytes(&c->parts, names->buf, names->length)) + retval = false; + +cleanup: + _mesa_string_buffer_destroy(names); + return retval; +} + +bool +dxil_container_add_state_validation(struct dxil_container *c, + const struct dxil_module *m, + struct dxil_validation_state *state) +{ + uint32_t psv1_size = sizeof(struct dxil_psv_runtime_info_1); + uint32_t resource_bind_info_size = 4 * sizeof(uint32_t); + uint32_t dxil_pvs_sig_size = sizeof(struct dxil_psv_signature_element); + uint32_t resource_count = state->num_resources; + + uint32_t size = psv1_size + 2 * sizeof(uint32_t); + if (resource_count > 0) { + size += sizeof (uint32_t) + + resource_bind_info_size * resource_count; + } + uint32_t string_table_size = (m->sem_string_table->length + 3) & ~3u; + size += sizeof(uint32_t) + string_table_size; + + // Semantic index table size, currently always 0 + size += sizeof(uint32_t) + m->sem_index_table.size * sizeof(uint32_t); + + if (m->num_sig_inputs || m->num_sig_outputs) { + size += sizeof(uint32_t); + } + + size += dxil_pvs_sig_size * m->num_sig_inputs; + size += dxil_pvs_sig_size * m->num_sig_outputs; + // size += dxil_pvs_sig_size * m->num_sig_patch_const...; + + state->state.sig_input_vectors = (uint8_t)m->num_psv_inputs; + + // TODO: check proper stream + state->state.sig_output_vectors[0] = (uint8_t)m->num_psv_outputs; + + // TODO: Add viewID records size + + // TODO: Add sig input output dependency table size + uint32_t dependency_table_size = 0; + if (state->state.sig_input_vectors > 0) { + for (unsigned i = 0; i < 4; ++i) { + if (state->state.sig_output_vectors[i] > 0) + dependency_table_size += sizeof(uint32_t) * ((state->state.sig_output_vectors[i] + 7) >> 3) * + state->state.sig_input_vectors * 4; + } + } + size += dependency_table_size; + // TODO: Domain shader table goes here + + if (!add_part_header(c, DXIL_PSV0, size)) + return false; + + if (!blob_write_bytes(&c->parts, &psv1_size, sizeof(psv1_size))) + return false; + + if (!blob_write_bytes(&c->parts, &state->state, psv1_size)) + return false; + + if (!blob_write_bytes(&c->parts, &resource_count, sizeof(resource_count))) + return false; + + if (resource_count > 0) { + if (!blob_write_bytes(&c->parts, &resource_bind_info_size, sizeof(resource_bind_info_size)) || + !blob_write_bytes(&c->parts, state->resources, resource_bind_info_size * state->num_resources)) + return false; + } + + + uint32_t fill = 0; + if (!blob_write_bytes(&c->parts, &string_table_size, sizeof(string_table_size)) || + !blob_write_bytes(&c->parts, m->sem_string_table->buf, m->sem_string_table->length) || + !blob_write_bytes(&c->parts, &fill, string_table_size - m->sem_string_table->length)) + return false; + + // TODO: write the correct semantic index table. Currently it is empty + if (!blob_write_bytes(&c->parts, &m->sem_index_table.size, sizeof(uint32_t))) + return false; + + if (m->sem_index_table.size > 0) { + if (!blob_write_bytes(&c->parts, m->sem_index_table.data, + m->sem_index_table.size * sizeof(uint32_t))) + return false; + } + + if (m->num_sig_inputs || m->num_sig_outputs) { + if (!blob_write_bytes(&c->parts, &dxil_pvs_sig_size, sizeof(dxil_pvs_sig_size))) + return false; + + if (!blob_write_bytes(&c->parts, &m->psv_inputs, dxil_pvs_sig_size * m->num_sig_inputs)) + return false; + + if (!blob_write_bytes(&c->parts, &m->psv_outputs, dxil_pvs_sig_size * m->num_sig_outputs)) + return false; + } + + // TODO: Write PatchConst... + + // TODO: Handle case when ViewID is used + + // TODO: Handle sig input output dependency table + + for (uint32_t i = 0; i < dependency_table_size; ++i) + blob_write_uint8(&c->parts, 0); + + return true; +} + +bool +dxil_container_add_module(struct dxil_container *c, + const struct dxil_module *m) +{ + assert(m->buf.buf_bits == 0); // make sure the module is fully flushed + uint32_t version = (m->shader_kind << 16) | + (m->major_version << 4) | + m->minor_version; + uint32_t size = 6 * sizeof(uint32_t) + m->buf.blob.size; + assert(size % sizeof(uint32_t) == 0); + uint32_t uint32_size = size / sizeof(uint32_t); + uint32_t magic = 0x4C495844; + uint32_t dxil_version = 1 << 8; // I have no idea... + uint32_t bitcode_offset = 16; + uint32_t bitcode_size = m->buf.blob.size; + + return add_part_header(c, DXIL_DXIL, size) && + blob_write_bytes(&c->parts, &version, sizeof(version)) && + blob_write_bytes(&c->parts, &uint32_size, sizeof(uint32_size)) && + blob_write_bytes(&c->parts, &magic, sizeof(magic)) && + blob_write_bytes(&c->parts, &dxil_version, sizeof(dxil_version)) && + blob_write_bytes(&c->parts, &bitcode_offset, sizeof(bitcode_offset)) && + blob_write_bytes(&c->parts, &bitcode_size, sizeof(bitcode_size)) && + blob_write_bytes(&c->parts, m->buf.blob.data, m->buf.blob.size); +} + +bool +dxil_container_write(struct dxil_container *c, struct blob *blob) +{ + assert(blob->size == 0); + if (!blob_write_bytes(blob, &DXIL_DXBC, sizeof(DXIL_DXBC))) + return false; + + const uint8_t unsigned_digest[16] = { 0 }; // null-digest means unsigned + if (!blob_write_bytes(blob, unsigned_digest, sizeof(unsigned_digest))) + return false; + + uint16_t major_version = 1; + uint16_t minor_version = 0; + if (!blob_write_bytes(blob, &major_version, sizeof(major_version)) || + !blob_write_bytes(blob, &minor_version, sizeof(minor_version))) + return false; + + size_t header_size = 32 + 4 * c->num_parts; + size_t size = header_size + c->parts.size; + assert(size <= UINT32_MAX); + uint32_t container_size = (uint32_t)size; + if (!blob_write_bytes(blob, &container_size, sizeof(container_size))) + return false; + + uint32_t part_offsets[DXIL_MAX_PARTS]; + for (int i = 0; i < c->num_parts; ++i) { + size_t offset = header_size + c->part_offsets[i]; + assert(offset <= UINT32_MAX); + part_offsets[i] = (uint32_t)offset; + } + + if (!blob_write_bytes(blob, &c->num_parts, sizeof(c->num_parts)) || + !blob_write_bytes(blob, part_offsets, sizeof(uint32_t) * c->num_parts) || + !blob_write_bytes(blob, c->parts.data, c->parts.size)) + return false; + + return true; +} diff --git a/src/microsoft/compiler/dxil_container.h b/src/microsoft/compiler/dxil_container.h new file mode 100644 index 00000000000..6c1a3783109 --- /dev/null +++ b/src/microsoft/compiler/dxil_container.h @@ -0,0 +1,123 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#ifndef DXIL_CONTAINER_H +#define DXIL_CONTAINER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "util/blob.h" + +#include "dxil_signature.h" + +#define DXIL_MAX_PARTS 8 +struct dxil_container { + struct blob parts; + unsigned part_offsets[DXIL_MAX_PARTS]; + unsigned num_parts; +}; + +enum dxil_resource_type { + DXIL_RES_INVALID = 0, + DXIL_RES_SAMPLER = 1, + DXIL_RES_CBV = 2, + DXIL_RES_SRV_TYPED = 3, + DXIL_RES_SRV_RAW = 4, + DXIL_RES_SRC_STRUCTURED = 5, + DXIL_RES_UAV_TYPED = 6, + DXIL_RES_UAV_RAW = 7, + DXIL_RES_UAV_STRUCTURED, + DXIL_RES_UAV_STRUCTURED_WITH_COUNTER, + DXIL_RES_NUM_ENTRIES /* should always be last */ +}; + +#define DXIL_FOURCC(ch0, ch1, ch2, ch3) ( \ + (uint32_t)(ch0) | (uint32_t)(ch1) << 8 | \ + (uint32_t)(ch2) << 16 | (uint32_t)(ch3) << 24) + +enum dxil_part_fourcc { + DXIL_RDEF = DXIL_FOURCC('R', 'D', 'E', 'F'), + DXIL_ISG1 = DXIL_FOURCC('I', 'S', 'G', '1'), + DXIL_OSG1 = DXIL_FOURCC('O', 'S', 'G', '1'), + DXIL_PSG1 = DXIL_FOURCC('P', 'S', 'G', '1'), + DXIL_STAT = DXIL_FOURCC('S', 'T', 'A', 'T'), + DXIL_ILDB = DXIL_FOURCC('I', 'L', 'D', 'B'), + DXIL_ILDN = DXIL_FOURCC('I', 'L', 'D', 'N'), + DXIL_SFI0 = DXIL_FOURCC('S', 'F', 'I', '0'), + DXIL_PRIV = DXIL_FOURCC('P', 'R', 'I', 'V'), + DXIL_RTS0 = DXIL_FOURCC('R', 'T', 'S', '0'), + DXIL_DXIL = DXIL_FOURCC('D', 'X', 'I', 'L'), + DXIL_PSV0 = DXIL_FOURCC('P', 'S', 'V', '0'), + DXIL_RDAT = DXIL_FOURCC('R', 'D', 'A', 'T'), + DXIL_HASH = DXIL_FOURCC('H', 'A', 'S', 'H'), +}; + +struct dxil_resource { + uint32_t resource_type; + uint32_t space; + uint32_t lower_bound; + uint32_t upper_bound; +}; + +struct dxil_validation_state { + struct dxil_psv_runtime_info_1 state; + const struct dxil_resource *resources; + uint32_t num_resources; +}; + +void +dxil_container_init(struct dxil_container *c); + +void +dxil_container_finish(struct dxil_container *c); + +bool +dxil_container_add_features(struct dxil_container *c, + const struct dxil_features *features); + + +bool +dxil_container_add_io_signature(struct dxil_container *c, + enum dxil_part_fourcc part, + unsigned num_records, + struct dxil_signature_record *io); + +bool +dxil_container_add_state_validation(struct dxil_container *c, + const struct dxil_module *m, + struct dxil_validation_state *state); + +bool +dxil_container_add_module(struct dxil_container *c, + const struct dxil_module *m); + +bool +dxil_container_write(struct dxil_container *c, struct blob *blob); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/microsoft/compiler/dxil_dump.c b/src/microsoft/compiler/dxil_dump.c new file mode 100644 index 00000000000..46c702c7ba4 --- /dev/null +++ b/src/microsoft/compiler/dxil_dump.c @@ -0,0 +1,778 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#include "dxil_dump.h" +#include "dxil_internal.h" + +#define DIXL_DUMP_DECL +#include "dxil_dump_decls.h" + +#include "dxil_module.h" + + +#include "util/string_buffer.h" +#include "util/list.h" + +#include + +struct dxil_dumper { + struct _mesa_string_buffer *buf; + int current_indent; +}; + +struct dxil_dumper *dxil_dump_create(void) +{ + struct dxil_dumper *d = calloc(1, sizeof(struct dxil_dumper)); + d->buf = _mesa_string_buffer_create(NULL, 1024); + d->current_indent = 0; + return d; +} + +void dxil_dump_free(struct dxil_dumper *d) +{ + _mesa_string_buffer_destroy(d->buf); + d->buf = 0; + free(d); +} + +void dxil_dump_buf_to_file(struct dxil_dumper *d, FILE *f) +{ + assert(f); + assert(d); + assert(d->buf); + fprintf(f, "%s", d->buf->buf); +} + +static +void dxil_dump_indention_inc(struct dxil_dumper *d) +{ + ++d->current_indent; +} + +static +void dxil_dump_indention_dec(struct dxil_dumper *d) +{ + --d->current_indent; + assert(d->current_indent >= 0); +} + +static +void dxil_dump_indent(struct dxil_dumper *d) +{ + for (int i = 0; i < 2 * d->current_indent; ++i) + _mesa_string_buffer_append_char(d->buf, ' '); +} + +void +dxil_dump_module(struct dxil_dumper *d, struct dxil_module *m) +{ + assert(m); + assert(d); + + _mesa_string_buffer_printf(d->buf, "DXIL MODULE:\n"); + dump_metadata(d, m); + dump_shader_info(d, &m->info); + dump_types(d, &m->type_list); + dump_gvars(d, &m->gvar_list); + dump_funcs(d, &m->func_list); + dump_attr_set_list(d, &m->attr_set_list); + dump_constants(d, &m->const_list); + dump_instrs(d, &m->instr_list); + dump_mdnodes(d, &m->mdnode_list); + dump_named_nodes(d, &m->md_named_node_list); + dump_io_signatures(d->buf, m); + dump_psv(d->buf, m); + _mesa_string_buffer_printf(d->buf, "END DXIL MODULE\n"); +} + +static void +dump_metadata(struct dxil_dumper *d, struct dxil_module *m) +{ + _mesa_string_buffer_printf(d->buf, "Shader: %s\n", + dump_shader_string(m->shader_kind)); + + _mesa_string_buffer_printf(d->buf, "Version: %d.%d\n", + m->major_version, m->minor_version); + + dump_features(d->buf, &m->feats); +} + +static void +dump_shader_info(struct dxil_dumper *d, struct dxil_shader_info *info) +{ + _mesa_string_buffer_append(d->buf, "Shader Info:\n"); + if (info->has_out_position) + _mesa_string_buffer_append(d->buf, " has_out_position\n"); +} + +static const char * +dump_shader_string(enum dxil_shader_kind kind) +{ +#define SHADER_STR(X) case DXIL_ ## X ## _SHADER: return #X + + switch (kind) { + SHADER_STR(VERTEX); + SHADER_STR(PIXEL); + SHADER_STR(GEOMETRY); + SHADER_STR(COMPUTE); + default: + return "UNSUPPORTED"; + } +#undef SHADER_STR +} + +static void +dump_features(struct _mesa_string_buffer *buf, struct dxil_features *feat) +{ + _mesa_string_buffer_printf(buf, "Features:\n"); +#define PRINT_FEAT(F) if (feat->F) _mesa_string_buffer_printf(buf, " %s\n", #F) + PRINT_FEAT(doubles); + PRINT_FEAT(cs_4x_raw_sb); + PRINT_FEAT(uavs_at_every_stage); + PRINT_FEAT(use_64uavs); + PRINT_FEAT(min_precision); + PRINT_FEAT(dx11_1_double_extensions); + PRINT_FEAT(dx11_1_shader_extensions); + PRINT_FEAT(dx9_comparison_filtering); + PRINT_FEAT(tiled_resources); + PRINT_FEAT(stencil_ref); + PRINT_FEAT(inner_coverage); + PRINT_FEAT(typed_uav_load_additional_formats); + PRINT_FEAT(rovs); + PRINT_FEAT(array_layer_from_vs_or_ds); + PRINT_FEAT(wave_ops); + PRINT_FEAT(int64_ops); + PRINT_FEAT(view_id); + PRINT_FEAT(barycentrics); + PRINT_FEAT(native_low_precision); + PRINT_FEAT(shading_rate); + PRINT_FEAT(raytracing_tier_1_1); + PRINT_FEAT(sampler_feedback); +#undef PRINT_FEAT +} + +static void +dump_types(struct dxil_dumper *d, struct list_head *list) +{ + if (!list_length(list)) + return; + + _mesa_string_buffer_append(d->buf, "Types:\n"); + dxil_dump_indention_inc(d); + list_for_each_entry(struct dxil_type, type, list, head) { + dxil_dump_indent(d); + dump_type(d, type); + _mesa_string_buffer_append(d->buf, "\n"); + } + dxil_dump_indention_dec(d); +} + +static void dump_type_name(struct dxil_dumper *d, const struct dxil_type *type) +{ + if (!type) { + _mesa_string_buffer_append(d->buf, "(type error)"); + return; + } + + switch (type->type) { + case TYPE_VOID: + _mesa_string_buffer_append(d->buf, "void"); + break; + case TYPE_INTEGER: + _mesa_string_buffer_printf(d->buf, "int%d", type->int_bits); + break; + case TYPE_FLOAT: + _mesa_string_buffer_printf(d->buf, "float%d", type->float_bits); + break; + case TYPE_POINTER: + dump_type_name(d, type->ptr_target_type); + _mesa_string_buffer_append(d->buf, "*"); + break; + case TYPE_STRUCT: + _mesa_string_buffer_printf(d->buf, "struct %s", type->struct_def.name); + break; + case TYPE_ARRAY: + dump_type_name(d, type->array_or_vector_def.elem_type); + _mesa_string_buffer_printf(d->buf, "[%d]", type->array_or_vector_def.num_elems); + break; + case TYPE_FUNCTION: + _mesa_string_buffer_append(d->buf, "("); + dump_type_name(d, type->function_def.ret_type); + _mesa_string_buffer_append(d->buf, ")("); + for (size_t i = 0; i < type->function_def.args.num_types; ++i) { + if (i > 0) + _mesa_string_buffer_append(d->buf, ", "); + dump_type_name(d, type->function_def.args.types[i]); + } + _mesa_string_buffer_append(d->buf, ")"); + break; + case TYPE_VECTOR: + _mesa_string_buffer_append(d->buf, "vector<"); + dump_type_name(d, type->array_or_vector_def.elem_type); + _mesa_string_buffer_printf(d->buf, ", %d>", type->array_or_vector_def.num_elems); + break; + default: + _mesa_string_buffer_printf(d->buf, "unknown type %d", type->type); + } +} + +static void +dump_type(struct dxil_dumper *d, const struct dxil_type *type) +{ + switch (type->type) { + case TYPE_STRUCT: + _mesa_string_buffer_printf(d->buf, "struct %s {\n", type->struct_def.name); + dxil_dump_indention_inc(d); + + for (size_t i = 0; i < type->struct_def.elem.num_types; ++i) { + dxil_dump_indent(d); + dump_type(d, type->struct_def.elem.types[i]); + _mesa_string_buffer_append(d->buf, "\n"); + } + dxil_dump_indention_dec(d); + dxil_dump_indent(d); + _mesa_string_buffer_append(d->buf, "}\n"); + break; + default: + dump_type_name(d, type); + break; + } +} + +static void +dump_gvars(struct dxil_dumper *d, struct list_head *list) +{ + if (!list_length(list)) + return; + + _mesa_string_buffer_append(d->buf, "Global variables:\n"); + dxil_dump_indention_inc(d); + list_for_each_entry(struct dxil_gvar, gvar, list, head) { + dxil_dump_indent(d); + _mesa_string_buffer_printf(d->buf, "address_space(%d) ", gvar->as); + if (gvar->constant) + _mesa_string_buffer_append(d->buf, "const "); + if (gvar->align) + _mesa_string_buffer_append(d->buf, "align "); + if (gvar->initializer) + _mesa_string_buffer_printf(d->buf, "init_id:%d\n", gvar->initializer->id); + dump_type_name(d, gvar->type); + _mesa_string_buffer_printf(d->buf, " val_id:%d\n", gvar->value.id); + } + dxil_dump_indention_dec(d); +} + +static void +dump_funcs(struct dxil_dumper *d, struct list_head *list) +{ + if (!list_length(list)) + return; + + _mesa_string_buffer_append(d->buf, "Functions:\n"); + dxil_dump_indention_inc(d); + list_for_each_entry(struct dxil_func, func, list, head) { + dxil_dump_indent(d); + if (func->decl) + _mesa_string_buffer_append(d->buf, "declare "); + _mesa_string_buffer_append(d->buf, func->name); + _mesa_string_buffer_append_char(d->buf, ' '); + dump_type_name(d, func->type); + if (func->attr_set) + _mesa_string_buffer_printf(d->buf, " #%d", func->attr_set); + _mesa_string_buffer_append_char(d->buf, '\n'); + } + dxil_dump_indention_dec(d); +} + +static void +dump_attr_set_list(struct dxil_dumper *d, struct list_head *list) +{ + if (!list_length(list)) + return; + + _mesa_string_buffer_append(d->buf, "Attribute set:\n"); + dxil_dump_indention_inc(d); + int attr_id = 1; + list_for_each_entry(struct attrib_set, attr, list, head) { + _mesa_string_buffer_printf(d->buf, " #%d: {", attr_id++); + for (unsigned i = 0; i < attr->num_attrs; ++i) { + if (i > 0) + _mesa_string_buffer_append_char(d->buf, ' '); + + assert(attr->attrs[i].type == DXIL_ATTR_ENUM); + const char *value = ""; + switch (attr->attrs[i].kind) { + case DXIL_ATTR_KIND_NONE: value = "none"; break; + case DXIL_ATTR_KIND_NO_UNWIND: value = "nounwind"; break; + case DXIL_ATTR_KIND_READ_NONE: value = "readnone"; break; + case DXIL_ATTR_KIND_READ_ONLY: value = "readonly"; break; + } + _mesa_string_buffer_append(d->buf, value); + } + _mesa_string_buffer_append(d->buf, "}\n"); + } + dxil_dump_indention_dec(d); +} + +static void +dump_constants(struct dxil_dumper *d, struct list_head *list) +{ + if (!list_length(list)) + return; + + _mesa_string_buffer_append(d->buf, "Constants:\n"); + dxil_dump_indention_inc(d); + list_for_each_entry(struct dxil_const, cnst, list, head) { + _mesa_string_buffer_append_char(d->buf, ' '); + dump_value(d, &cnst->value); + _mesa_string_buffer_append(d->buf, " = "); + dump_type_name(d, cnst->value.type); + if (!cnst->undef) { + switch (cnst->value.type->type) { + case TYPE_FLOAT: + _mesa_string_buffer_printf(d->buf, " %10.5f\n", cnst->float_value); + break; + case TYPE_INTEGER: + _mesa_string_buffer_printf(d->buf, " %d\n", cnst->int_value); + break; + case TYPE_ARRAY: + _mesa_string_buffer_append(d->buf, "{"); + for (unsigned i = 0; + i < cnst->value.type->array_or_vector_def.num_elems; i++) { + _mesa_string_buffer_printf(d->buf, " %%%d", + cnst->array_values[i]->id); + dump_type_name(d, cnst->value.type); + if (i != cnst->value.type->array_or_vector_def.num_elems - 1) + _mesa_string_buffer_append(d->buf, ","); + _mesa_string_buffer_append(d->buf, " "); + } + _mesa_string_buffer_append(d->buf, "}\n"); + break; + default: + unreachable("Unsupported const type"); + } + } else + _mesa_string_buffer_append(d->buf, " undef\n"); + } + dxil_dump_indention_dec(d); +} + +static void +dump_instrs(struct dxil_dumper *d, struct list_head *list) +{ + _mesa_string_buffer_append(d->buf, "Shader body:\n"); + dxil_dump_indention_inc(d); + + list_for_each_entry(struct dxil_instr, instr, list, head) { + + dxil_dump_indent(d); + if (instr->has_value) { + dump_value(d, &instr->value); + _mesa_string_buffer_append(d->buf, " = "); + } else { + _mesa_string_buffer_append_char(d->buf, ' '); + } + + switch (instr->type) { + case INSTR_BINOP: dump_instr_binop(d, &instr->binop); break; + case INSTR_CMP: dump_instr_cmp(d, &instr->cmp);break; + case INSTR_SELECT:dump_instr_select(d, &instr->select); break; + case INSTR_CAST: dump_instr_cast(d, &instr->cast); break; + case INSTR_CALL: dump_instr_call(d, &instr->call); break; + case INSTR_RET: dump_instr_ret(d, &instr->ret); break; + case INSTR_EXTRACTVAL: dump_instr_extractval(d, &instr->extractval); break; + case INSTR_BR: dump_instr_branch(d, &instr->br); break; + case INSTR_PHI: dump_instr_phi(d, &instr->phi); break; + case INSTR_ALLOCA: dump_instr_alloca(d, &instr->alloca); break; + case INSTR_GEP: dump_instr_gep(d, &instr->gep); break; + case INSTR_LOAD: dump_instr_load(d, &instr->load); break; + case INSTR_STORE: dump_instr_store(d, &instr->store); break; + case INSTR_ATOMICRMW: dump_instr_atomicrmw(d, &instr->atomicrmw); break; + default: + _mesa_string_buffer_printf(d->buf, "unknown instruction type %d", instr->type); + } + + _mesa_string_buffer_append(d->buf, "\n"); + } + dxil_dump_indention_dec(d); +} + +static void +dump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop) +{ + const char *str = binop->opcode < DXIL_BINOP_INSTR_COUNT ? + binop_strings[binop->opcode] : "INVALID"; + + _mesa_string_buffer_printf(d->buf, "%s ", str); + dump_instr_print_operands(d, 2, binop->operands); +} + +static void +dump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp) +{ + const char *str = cmp->pred < DXIL_CMP_INSTR_COUNT ? + pred_strings[cmp->pred] : "INVALID"; + + _mesa_string_buffer_printf(d->buf, "%s ", str); + dump_instr_print_operands(d, 2, cmp->operands); +} + +static void +dump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select) +{ + _mesa_string_buffer_append(d->buf, "sel "); + dump_instr_print_operands(d, 3, select->operands); +} + +static void +dump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast) +{ + const char *str = cast->opcode < DXIL_CAST_INSTR_COUNT ? + cast_opcode_strings[cast->opcode] : "INVALID"; + + _mesa_string_buffer_printf(d->buf, "%s.", str); + dump_type_name(d, cast->type); + _mesa_string_buffer_append_char(d->buf, ' '); + dump_value(d, cast->value); +} + +static void +dump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call) +{ + assert(call->num_args == call->func->type->function_def.args.num_types); + struct dxil_type **func_arg_types = call->func->type->function_def.args.types; + + _mesa_string_buffer_printf(d->buf, "%s(", call->func->name); + for (unsigned i = 0; i < call->num_args; ++i) { + if (i > 0) + _mesa_string_buffer_append(d->buf, ", "); + dump_type_name(d, func_arg_types[i]); + _mesa_string_buffer_append_char(d->buf, ' '); + dump_value(d, call->args[i]); + } + _mesa_string_buffer_append_char(d->buf, ')'); +} + +static void +dump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret) +{ + _mesa_string_buffer_append(d->buf, "ret "); + if (ret->value) + dump_value(d, ret->value); +} + +static void +dump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *extr) +{ + _mesa_string_buffer_append(d->buf, "extractvalue "); + dump_type_name(d, extr->type); + dump_value(d, extr->src); + _mesa_string_buffer_printf(d->buf, ", %d", extr->idx); +} + +static void +dump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br) +{ + _mesa_string_buffer_append(d->buf, "branch "); + if (br->cond) + dump_value(d, br->cond); + else + _mesa_string_buffer_append(d->buf, " (uncond)"); + _mesa_string_buffer_printf(d->buf, " %d %d", br->succ[0], br->succ[1]); +} + +static void +dump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi) +{ + _mesa_string_buffer_append(d->buf, "phi "); + dump_type_name(d, phi->type); + struct dxil_phi_src *src = phi->incoming; + for (unsigned i = 0; i < phi->num_incoming; ++i, ++src) { + if (i > 0) + _mesa_string_buffer_append(d->buf, ", "); + dump_value(d, src->value); + _mesa_string_buffer_printf(d->buf, "(%d)", src->block); + } +} + +static void +dump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca) +{ + _mesa_string_buffer_append(d->buf, "alloca "); + dump_type_name(d, alloca->alloc_type); + _mesa_string_buffer_append(d->buf, ", "); + dump_type_name(d, alloca->size_type); + _mesa_string_buffer_append(d->buf, ", "); + dump_value(d, alloca->size); + unsigned align_mask = (1 << 6 ) - 1; + unsigned align = alloca->align & align_mask; + _mesa_string_buffer_printf(d->buf, ", %d", 1 << (align - 1)); +} + +static void +dump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep) +{ + _mesa_string_buffer_append(d->buf, "getelementptr "); + if (gep->inbounds) + _mesa_string_buffer_append(d->buf, "inbounds "); + dump_type_name(d, gep->source_elem_type); + _mesa_string_buffer_append(d->buf, ", "); + for (unsigned i = 0; i < gep->num_operands; ++i) { + if (i > 0) + _mesa_string_buffer_append(d->buf, ", "); + dump_value(d, gep->operands[i]); + } +} + +static void +dump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *load) +{ + _mesa_string_buffer_append(d->buf, "load "); + if (load->is_volatile) + _mesa_string_buffer_append(d->buf, " volatile"); + dump_type_name(d, load->type); + _mesa_string_buffer_append(d->buf, ", "); + dump_value(d, load->ptr); + _mesa_string_buffer_printf(d->buf, ", %d", load->align); +} + +static void +dump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store) +{ + _mesa_string_buffer_append(d->buf, "store "); + if (store->is_volatile) + _mesa_string_buffer_append(d->buf, " volatile"); + dump_value(d, store->value); + _mesa_string_buffer_append(d->buf, ", "); + dump_value(d, store->ptr); + _mesa_string_buffer_printf(d->buf, ", %d", store->align); +} + +static const char *rmworder_str[] = { + [DXIL_ATOMIC_ORDERING_NOTATOMIC] = "not-atomic", + [DXIL_ATOMIC_ORDERING_UNORDERED] = "unordered", + [DXIL_ATOMIC_ORDERING_MONOTONIC] = "monotonic", + [DXIL_ATOMIC_ORDERING_ACQUIRE] = "acquire", + [DXIL_ATOMIC_ORDERING_RELEASE] = "release", + [DXIL_ATOMIC_ORDERING_ACQREL] = "acqrel", + [DXIL_ATOMIC_ORDERING_SEQCST] = "seqcst", +}; + +static const char *rmwsync_str[] = { + [DXIL_SYNC_SCOPE_SINGLETHREAD] = "single-thread", + [DXIL_SYNC_SCOPE_CROSSTHREAD] = "cross-thread", +}; + +static const char *rmwop_str[] = { + [DXIL_RMWOP_XCHG] = "xchg", + [DXIL_RMWOP_ADD] = "add", + [DXIL_RMWOP_SUB] = "sub", + [DXIL_RMWOP_AND] = "and", + [DXIL_RMWOP_NAND] = "nand", + [DXIL_RMWOP_OR] = "or", + [DXIL_RMWOP_XOR] = "xor", + [DXIL_RMWOP_MAX] = "max", + [DXIL_RMWOP_MIN] = "min", + [DXIL_RMWOP_UMAX] = "umax", + [DXIL_RMWOP_UMIN] = "umin", +}; + +static void +dump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw) +{ + _mesa_string_buffer_printf(d->buf, "atomicrmw.%s ", rmwop_str[rmw->op]); + + if (rmw->is_volatile) + _mesa_string_buffer_append(d->buf, " volatile"); + dump_value(d, rmw->value); + _mesa_string_buffer_append(d->buf, ", "); + dump_value(d, rmw->ptr); + _mesa_string_buffer_printf(d->buf, ", ordering(%s)", rmworder_str[rmw->ordering]); + _mesa_string_buffer_printf(d->buf, ", sync_scope(%s)", rmwsync_str[rmw->syncscope]); +} + +static void +dump_instr_print_operands(struct dxil_dumper *d, int num, + const struct dxil_value *val[]) +{ + for (int i = 0; i < num; ++i) { + if (i > 0) + _mesa_string_buffer_append(d->buf, ", "); + dump_value(d, val[i]); + } +} + +static void +dump_value(struct dxil_dumper *d, const struct dxil_value *val) +{ + if (val->id < 10) + _mesa_string_buffer_append(d->buf, " "); + if (val->id < 100) + _mesa_string_buffer_append(d->buf, " "); + _mesa_string_buffer_printf(d->buf, "%%%d", val->id); + dump_type_name(d, val->type); +} + +static void +dump_mdnodes(struct dxil_dumper *d, struct list_head *list) +{ + if (!list_length(list)) + return; + + _mesa_string_buffer_append(d->buf, "MD-Nodes:\n"); + dxil_dump_indention_inc(d); + list_for_each_entry(struct dxil_mdnode, node, list, head) { + dump_mdnode(d, node); + } + dxil_dump_indention_dec(d); +} + +static void +dump_mdnode(struct dxil_dumper *d, struct dxil_mdnode *node) +{ + dxil_dump_indent(d); + switch (node->type) { + case MD_STRING: + _mesa_string_buffer_printf(d->buf, "S:%s\n", node->string); + break; + case MD_VALUE: + _mesa_string_buffer_append(d->buf, "V:"); + dump_type_name(d, node->value.type); + _mesa_string_buffer_append_char(d->buf, ' '); + dump_value(d, node->value.value); + _mesa_string_buffer_append_char(d->buf, '\n'); + break; + case MD_NODE: + _mesa_string_buffer_append(d->buf, " \\\n"); + dxil_dump_indention_inc(d); + for (size_t i = 0; i < node->node.num_subnodes; ++i) { + if (node->node.subnodes[i]) + dump_mdnode(d, node->node.subnodes[i]); + else { + dxil_dump_indent(d); + _mesa_string_buffer_append(d->buf, "(nullptr)\n"); + } + } + dxil_dump_indention_dec(d); + break; + } +} + +static void +dump_named_nodes(struct dxil_dumper *d, struct list_head *list) +{ + if (!list_length(list)) + return; + + _mesa_string_buffer_append(d->buf, "Named Nodes:\n"); + dxil_dump_indention_inc(d); + list_for_each_entry(struct dxil_named_node, node, list, head) { + dxil_dump_indent(d); + _mesa_string_buffer_printf(d->buf, "%s:\n", node->name); + dxil_dump_indention_inc(d); + for (size_t i = 0; i < node->num_subnodes; ++i) { + if (node->subnodes[i]) + dump_mdnode(d, node->subnodes[i]); + else { + dxil_dump_indent(d); + _mesa_string_buffer_append(d->buf, "(nullptr)\n"); + } + } + dxil_dump_indention_dec(d); + } + dxil_dump_indention_dec(d); +} + +static void +mask_to_string(uint32_t mask, char str[5]) +{ + const char *mc = "xyzw"; + for (int i = 0; i < 4 && mask; ++i) { + str[i] = (mask & (1 << i)) ? mc[i] : '_'; + } + str[4] = 0; +} + +static void dump_io_signatures(struct _mesa_string_buffer *buf, struct dxil_module *m) +{ + _mesa_string_buffer_append(buf, "\nInput signature:\n"); + dump_io_signature(buf, m->num_sig_inputs, m->inputs); + _mesa_string_buffer_append(buf, "\nOutput signature:\n"); + dump_io_signature(buf, m->num_sig_outputs, m->outputs); +} + +static void dump_io_signature(struct _mesa_string_buffer *buf, unsigned num, + struct dxil_signature_record *io) +{ + _mesa_string_buffer_append(buf, " SEMANTIC-NAME Index Mask Reg SysValue Format\n"); + _mesa_string_buffer_append(buf, "----------------------------------------------\n"); + for (unsigned i = 0; i < num; ++i, ++io) { + for (unsigned j = 0; j < io->num_elements; ++j) { + char mask[5] = ""; + mask_to_string(io->elements[j].mask, mask); + _mesa_string_buffer_printf(buf, "%-15s %3d %4s %3d %-8s %-7s\n", + io->name, io->elements[j].semantic_index, + mask, io->elements[j].reg, io->sysvalue, + component_type_as_string(io->elements[j].comp_type)); + } + } +} + +static const char *component_type_as_string(uint32_t type) +{ + return (type < DXIL_PROG_SIG_COMP_TYPE_COUNT) ? + dxil_type_strings[type] : "invalid"; +} + +static void dump_psv(struct _mesa_string_buffer *buf, + struct dxil_module *m) +{ + _mesa_string_buffer_append(buf, "\nPipeline State Validation\nInputs:\n"); + dump_psv_io(buf, m, m->num_sig_inputs, m->psv_inputs); + _mesa_string_buffer_append(buf, "\nOutputs:\n"); + dump_psv_io(buf, m, m->num_sig_outputs, m->psv_outputs); +} + +static void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m, + unsigned num, struct dxil_psv_signature_element *io) +{ + _mesa_string_buffer_append(buf, " SEMANTIC-NAME Rows Cols Kind Comp-Type Interp dynmask+stream Indices\n"); + _mesa_string_buffer_append(buf, "----------------------------------------------\n"); + for (unsigned i = 0; i < num; ++i, ++io) { + _mesa_string_buffer_printf(buf, "%-14s %d+%d %d+%d %4d %-7s %-4d %-9d [", + m->sem_string_table->buf + io->semantic_name_offset, + (int)io->start_row, (int)io->rows, + (int)((io->cols_and_start & 0xf) >> 4), + (int)(io->cols_and_start & 0xf), + (int)io->semantic_kind, + component_type_as_string(io->component_type), + (int)io->interpolation_mode, + (int)io->dynamic_mask_and_stream); + for (int k = 0; k < io->rows; ++k) { + if (k > 0) + _mesa_string_buffer_append(buf, ", "); + _mesa_string_buffer_printf(buf,"%d ", m->sem_index_table.data[io->start_row + k]); + } + _mesa_string_buffer_append(buf, "]\n"); + } +} diff --git a/src/microsoft/compiler/dxil_dump.h b/src/microsoft/compiler/dxil_dump.h new file mode 100644 index 00000000000..6a4b26521e1 --- /dev/null +++ b/src/microsoft/compiler/dxil_dump.h @@ -0,0 +1,53 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#ifndef DXIL_DUMP_H +#define DXIL_DUMP_H + +#include +struct dxil_module; +struct _mesa_string_buffer; + + + +#ifdef __cplusplus +extern "C" { +#endif + +struct dxil_dumper; + +struct dxil_dumper *dxil_dump_create(void); + +void dxil_dump_free(struct dxil_dumper *d); + +void dxil_dump_buf_to_file(struct dxil_dumper *d, FILE *f); + +void +dxil_dump_module(struct dxil_dumper *d, struct dxil_module *m); + +#ifdef __cplusplus +} +#endif + + +#endif // DXIL_DUMP_H diff --git a/src/microsoft/compiler/dxil_dump_decls.h b/src/microsoft/compiler/dxil_dump_decls.h new file mode 100644 index 00000000000..889fe19756c --- /dev/null +++ b/src/microsoft/compiler/dxil_dump_decls.h @@ -0,0 +1,179 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#ifndef DIXL_DUMP_DECL +#error This header can only be included from dxil_dump.c +#endif + +#include "dxil_module.h" + +static void +dump_metadata(struct dxil_dumper *buf, struct dxil_module *m); +static void +dump_shader_info(struct dxil_dumper *buf, struct dxil_shader_info *info); +static const char * +dump_shader_string(enum dxil_shader_kind kind); +static void +dump_features(struct _mesa_string_buffer *buf, struct dxil_features *feat); +static void +dump_types(struct dxil_dumper *buf, struct list_head *list); +static void +dump_gvars(struct dxil_dumper *buf, struct list_head *list); +static void +dump_constants(struct dxil_dumper *buf, struct list_head *list); +static void +dump_funcs(struct dxil_dumper *buf, struct list_head *list); +static void +dump_attr_set_list(struct dxil_dumper *buf, struct list_head *list); +static void +dump_instrs(struct dxil_dumper *buf, struct list_head *list); +static void +dump_mdnodes(struct dxil_dumper *buf, struct list_head *list); +static void +dump_mdnode(struct dxil_dumper *d, struct dxil_mdnode *node); +static void +dump_named_nodes(struct dxil_dumper *d, struct list_head *list); +static void +dump_type(struct dxil_dumper *buf, const struct dxil_type *type); +static void +dump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop); +static void +dump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp); +static void +dump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select); +static void +dump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast); +static void +dump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call); +static void +dump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret); +static void +dump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *ret); +static void +dump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br); +static void +dump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi); +static void +dump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca); +static void +dump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep); +static void +dump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *store); +static void +dump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store); +static void +dump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw); + +static void +dump_instr_print_operands(struct dxil_dumper *d, int num, + const struct dxil_value *val[]); + +static void dump_io_signatures(struct _mesa_string_buffer *buf, + struct dxil_module *m); +static void +dump_io_signature(struct _mesa_string_buffer *buf, unsigned num, + struct dxil_signature_record *io); + +static const char *component_type_as_string(uint32_t type); + +static void dump_psv(struct _mesa_string_buffer *buf, + struct dxil_module *m); +static void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m, + unsigned num, struct dxil_psv_signature_element *io); + +static void +dump_value(struct dxil_dumper *d, const struct dxil_value *val); + +static const char *binop_strings[DXIL_BINOP_INSTR_COUNT] = { + [DXIL_BINOP_ADD] = "add", + [DXIL_BINOP_SUB] = "sub", + [DXIL_BINOP_MUL] = "mul", + [DXIL_BINOP_UDIV] = "udiv", + [DXIL_BINOP_SDIV] = "sdiv", + [DXIL_BINOP_UREM] = "urem", + [DXIL_BINOP_SREM] = "srem", + [DXIL_BINOP_SHL] = "shl", + [DXIL_BINOP_LSHR] = "lshr", + [DXIL_BINOP_ASHR] = "ashr", + [DXIL_BINOP_AND] = "and", + [DXIL_BINOP_OR] = "or", + [DXIL_BINOP_XOR]= "xor" +}; + +static const char *pred_strings[DXIL_CMP_INSTR_COUNT] = { + [DXIL_FCMP_FALSE] = "FALSE", + [DXIL_FCMP_OEQ] = "ord-fEQ", + [DXIL_FCMP_OGT] = "ord-fGT", + [DXIL_FCMP_OGE] = "ord-fGE", + [DXIL_FCMP_OLT] = "ord-fLT", + [DXIL_FCMP_OLE] = "ord-fLE", + [DXIL_FCMP_ONE] = "ord-fNE", + [DXIL_FCMP_ORD] = "ord-fRD", + [DXIL_FCMP_UNO] = "unord-fNO", + [DXIL_FCMP_UEQ] = "unord-fEQ", + [DXIL_FCMP_UGT] = "unord-fGT", + [DXIL_FCMP_UGE] = "unord-fGE", + [DXIL_FCMP_ULT] = "unord-fLT", + [DXIL_FCMP_ULE] = "unord-fLE", + [DXIL_FCMP_UNE] = "unord-fNE", + [DXIL_FCMP_TRUE] = "TRUE", + [DXIL_ICMP_EQ] = "iEQ", + [DXIL_ICMP_NE] = "iNE", + [DXIL_ICMP_UGT] = "uiGT", + [DXIL_ICMP_UGE] = "uiGE", + [DXIL_ICMP_ULT] = "uiLT", + [DXIL_ICMP_ULE] = "uiLE", + [DXIL_ICMP_SGT] = "iGT", + [DXIL_ICMP_SGE] = "iGE", + [DXIL_ICMP_SLT] = "iLT", + [DXIL_ICMP_SLE] = "iLE" +}; + +static const char *cast_opcode_strings[DXIL_CAST_INSTR_COUNT] = { + [DXIL_CAST_TRUNC] = "trunc", + [DXIL_CAST_ZEXT] = "zext", + [DXIL_CAST_SEXT] = "sext", + [DXIL_CAST_FPTOUI] = "ftoui", + [DXIL_CAST_FPTOSI] = "ftoi", + [DXIL_CAST_UITOFP] = "uitof", + [DXIL_CAST_SITOFP] = "itof", + [DXIL_CAST_FPTRUNC] = "ftrunc", + [DXIL_CAST_FPEXT] = "fext", + [DXIL_CAST_PTRTOINT] = "ptrtoint", + [DXIL_CAST_INTTOPTR] = "inttoptr", + [DXIL_CAST_BITCAST] = "bitcast", + [DXIL_CAST_ADDRSPACECAST] = "addrspacecast", +}; + +static const char *dxil_type_strings[DXIL_PROG_SIG_COMP_TYPE_COUNT] = { + [DXIL_PROG_SIG_COMP_TYPE_UNKNOWN] = "unknown", + [DXIL_PROG_SIG_COMP_TYPE_UINT32] = "uint32", + [DXIL_PROG_SIG_COMP_TYPE_SINT32] = "int32", + [DXIL_PROG_SIG_COMP_TYPE_FLOAT32] = "float32", + [DXIL_PROG_SIG_COMP_TYPE_UINT16] = "uint16", + [DXIL_PROG_SIG_COMP_TYPE_SINT16] = "int16", + [DXIL_PROG_SIG_COMP_TYPE_FLOAT16] = "float16", + [DXIL_PROG_SIG_COMP_TYPE_UINT64] = "uint64", + [DXIL_PROG_SIG_COMP_TYPE_SINT64] = "int64", + [DXIL_PROG_SIG_COMP_TYPE_FLOAT64] = "float64" +}; diff --git a/src/microsoft/compiler/dxil_enums.c b/src/microsoft/compiler/dxil_enums.c new file mode 100644 index 00000000000..b2a0b36b87a --- /dev/null +++ b/src/microsoft/compiler/dxil_enums.c @@ -0,0 +1,163 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#include "dxil_enums.h" + +#include "nir.h" +#include "nir_types.h" + +#include "util/u_debug.h" + +enum dxil_prog_sig_comp_type dxil_get_prog_sig_comp_type(const struct glsl_type *type) +{ + type = glsl_without_array(type); + + switch (glsl_get_base_type(type)) { + case GLSL_TYPE_UINT: return DXIL_PROG_SIG_COMP_TYPE_UINT32; + case GLSL_TYPE_INT: return DXIL_PROG_SIG_COMP_TYPE_SINT32; + case GLSL_TYPE_FLOAT: return DXIL_PROG_SIG_COMP_TYPE_FLOAT32; + case GLSL_TYPE_FLOAT16: return DXIL_PROG_SIG_COMP_TYPE_FLOAT16; + case GLSL_TYPE_DOUBLE: return DXIL_PROG_SIG_COMP_TYPE_FLOAT64; + case GLSL_TYPE_UINT16: return DXIL_PROG_SIG_COMP_TYPE_UINT16; + case GLSL_TYPE_INT16: return DXIL_PROG_SIG_COMP_TYPE_SINT16; + case GLSL_TYPE_UINT64: return DXIL_PROG_SIG_COMP_TYPE_UINT64; + case GLSL_TYPE_INT64: return DXIL_PROG_SIG_COMP_TYPE_SINT64; + case GLSL_TYPE_BOOL: return DXIL_PROG_SIG_COMP_TYPE_UINT32; + default: + debug_printf("unexpected type: %s\n", glsl_get_type_name(type)); + return DXIL_PROG_SIG_COMP_TYPE_UNKNOWN; + } +} + +enum dxil_component_type dxil_get_comp_type(const struct glsl_type *type) +{ + type = glsl_without_array(type); + + enum glsl_base_type base_type = glsl_get_base_type(type); + if (glsl_type_is_sampler(type) || glsl_type_is_image(type)) + base_type = glsl_get_sampler_result_type(type); + switch (base_type) { + case GLSL_TYPE_UINT: return DXIL_COMP_TYPE_U32; + case GLSL_TYPE_INT: return DXIL_COMP_TYPE_I32; + case GLSL_TYPE_FLOAT: return DXIL_COMP_TYPE_F32; + case GLSL_TYPE_FLOAT16: return DXIL_COMP_TYPE_F16; + case GLSL_TYPE_DOUBLE: return DXIL_COMP_TYPE_F64; + case GLSL_TYPE_UINT16: return DXIL_COMP_TYPE_U16; + case GLSL_TYPE_INT16: return DXIL_COMP_TYPE_I16; + case GLSL_TYPE_UINT64: return DXIL_COMP_TYPE_U64; + case GLSL_TYPE_INT64: return DXIL_COMP_TYPE_I64; + case GLSL_TYPE_BOOL: return DXIL_COMP_TYPE_I1; + + default: + debug_printf("type: %s\n", glsl_get_type_name(type)); + unreachable("unexpected glsl type"); + } +} + +enum dxil_resource_kind dxil_get_resource_kind(const struct glsl_type *type) +{ + type = glsl_without_array(type); + + /* This looks weird, we strip the arrays but then we still test whether it's + * an array, key is the first refers to sampler[] and the second to samplerArray */ + bool is_array = glsl_sampler_type_is_array(type); + + if (glsl_type_is_sampler(type) || glsl_type_is_image(type)) { + switch (glsl_get_sampler_dim(type)) { + case GLSL_SAMPLER_DIM_1D: + return is_array ? DXIL_RESOURCE_KIND_TEXTURE1D_ARRAY + : DXIL_RESOURCE_KIND_TEXTURE1D; + case GLSL_SAMPLER_DIM_2D: + return is_array ? DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY + : DXIL_RESOURCE_KIND_TEXTURE2D; + case GLSL_SAMPLER_DIM_3D: + return DXIL_RESOURCE_KIND_TEXTURE3D; + case GLSL_SAMPLER_DIM_CUBE: + return is_array ? DXIL_RESOURCE_KIND_TEXTURECUBE_ARRAY + : DXIL_RESOURCE_KIND_TEXTURECUBE; + case GLSL_SAMPLER_DIM_RECT: + return DXIL_RESOURCE_KIND_TEXTURE2D; + case GLSL_SAMPLER_DIM_BUF: + return DXIL_RESOURCE_KIND_TYPED_BUFFER; + case GLSL_SAMPLER_DIM_MS: + return is_array ? DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY + : DXIL_RESOURCE_KIND_TEXTURE2DMS; + + default: + debug_printf("type: %s\n", glsl_get_type_name(type)); + unreachable("unexpected sampler type"); + } + } + + debug_printf("type: %s\n", glsl_get_type_name(type)); + unreachable("unexpected glsl type"); +} + +enum dxil_input_primitive dxil_get_input_primitive(unsigned primitive) +{ + switch (primitive) { + case GL_POINTS: + return DXIL_INPUT_PRIMITIVE_POINT; + case GL_LINES: + return DXIL_INPUT_PRIMITIVE_LINE; + case GL_LINES_ADJACENCY: + return DXIL_INPUT_PRIMITIVE_LINES_ADJENCY; + case GL_TRIANGLES: + return DXIL_INPUT_PRIMITIVE_TRIANGLE; + case GL_TRIANGLES_ADJACENCY: + return DXIL_INPUT_PRIMITIVE_TRIANGLES_ADJENCY; + default: + unreachable("unhandled primitive topology"); + } +} + +enum dxil_primitive_topology dxil_get_primitive_topology(unsigned topology) +{ + switch (topology) { + case GL_POINTS: + return DXIL_PRIMITIVE_TOPOLOGY_POINT_LIST; + case GL_LINES: + return DXIL_PRIMITIVE_TOPOLOGY_LINE_LIST; + case GL_LINE_STRIP: + return DXIL_PRIMITIVE_TOPOLOGY_LINE_STRIP; + case GL_TRIANGLE_STRIP: + return DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + default: + unreachable("unhandled primitive topology"); + } +} + +static const char *overload_str[DXIL_NUM_OVERLOADS] = { + [DXIL_NONE] = "", + [DXIL_I16] = "i16", + [DXIL_I32] = "i32", + [DXIL_I64] = "i64", + [DXIL_F32] = "f32", + [DXIL_F64] = "f64", +}; + +const char *dxil_overload_suffix( enum overload_type overload) +{ + assert(overload < DXIL_NUM_OVERLOADS); + return overload_str[overload]; +} diff --git a/src/microsoft/compiler/dxil_enums.h b/src/microsoft/compiler/dxil_enums.h new file mode 100644 index 00000000000..921b5644e97 --- /dev/null +++ b/src/microsoft/compiler/dxil_enums.h @@ -0,0 +1,340 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#ifndef DIXL_ENUMS_H +#define DIXL_ENUMS_H + +enum dxil_signature_kind { + DXIL_SIG_INVALID = 0, + DXIL_SIG_INPUT, + DXIL_SIG_OUTPUT, + DXIL_SIG_PATCH_CONST_OR_PRIM +}; + +/* These enums are taken from + * DirectXShaderCompiler/lib/dxc/DXIL/DxilConstants.h + */ +enum dxil_semantic_kind { + DXIL_SEM_ARBITRARY, + DXIL_SEM_VERTEX_ID, + DXIL_SEM_INSTANCE_ID, + DXIL_SEM_POSITION, + DXIL_SEM_RENDERTARGET_ARRAY_INDEX, + DXIL_SEM_VIEWPORT_ARRAY_INDEX, + DXIL_SEM_CLIP_DISTANCE, + DXIL_SEM_CULL_DISTANCE, + DXIL_SEM_OUTPUT_CONTROL_POINT_ID, + DXIL_SEM_DOMAIN_LOCATION, + DXIL_SEM_PRIMITIVE_ID, + DXIL_SEM_GS_INSTANCE_ID, + DXIL_SEM_SAMPLE_INDEX, + DXIL_SEM_IS_FRONT_FACE, + DXIL_SEM_COVERAGE, + DXIL_SEM_INNER_COVERAGE, + DXIL_SEM_TARGET, + DXIL_SEM_DEPTH, + DXIL_SEM_DEPTH_LE, + DXIL_SEM_DEPTH_GE, + DXIL_SEM_STENCIL_REF, + DXIL_SEM_DISPATCH_THREAD_ID, + DXIL_SEM_GROUP_ID, + DXIL_SEM_GROUP_INDEX, + DXIL_SEM_GROUP_THREAD_ID, + DXIL_SEM_TESS_FACTOR, + DXIL_SEM_INSIDE_TESS_FACTOR, + DXIL_SEM_VIEW_ID, + DXIL_SEM_BARYCENTRICS, + DXIL_SEM_SHADING_RATE, + DXIL_SEM_CULL_PRIMITIVE, + DXIL_SEM_INVALID +}; + +enum dxil_prog_sig_semantic { + DXIL_PROG_SEM_UNDEFINED = 0, + DXIL_PROG_SEM_POSITION = 1, + DXIL_PROG_SEM_CLIP_DISTANCE = 2, + DXIL_PROG_SEM_CULL_DISTANCE = 3, + DXIL_PROG_SEM_RENDERTARGET_ARRAY_INDEX = 4, + DXIL_PROG_SEM_VIEWPORT_ARRAY_INDEX = 5, + DXIL_PROG_SEM_VERTEX_ID = 6, + DXIL_PROG_SEM_PRIMITIVE_ID = 7, + DXIL_PROG_SEM_INSTANCE_ID = 8, + DXIL_PROG_SEM_IS_FRONTFACE = 9, + DXIL_PROG_SEM_SAMPLE_INDEX = 10, + DXIL_PROG_SEM_FINAL_QUAD_EDGE_TESSFACTOR = 11, + DXIL_PROG_SEM_FINAL_QUAD_INSIDE_EDGE_TESSFACTOR = 12, + DXIL_PROG_SEM_FINAL_TRI_EDGE_TESSFACTOR = 13, + DXIL_PROG_SEM_FINAL_TRI_INSIDE_EDGE_TESSFACTOR = 14, + DXIL_PROG_SEM_FINAL_LINE_DETAIL_TESSFACTOR = 15, + DXIL_PROG_SEM_FINAL_LINE_DENSITY_TESSFACTOR = 16, + DXIL_PROG_SEM_BARYCENTRICS = 23, + DXIL_PROG_SEM_SHADING_RATE = 24, + DXIL_PROG_SEM_CULL_PRIMITIVE = 25, + DXIL_PROG_SEM_TARGET = 64, + DXIL_PROG_SEM_DEPTH = 65, + DXIL_PROG_SEM_COVERAGE = 66, + DXIL_PROG_SEM_DEPTH_GE = 67, + DXIL_PROG_SEM_DEPTH_LE = 68, + DXIL_PROG_SEM_STENCIL_REF = 69, + DXIL_PROG_SEM_INNER_COVERAGE = 70 +}; + +enum dxil_prog_sig_comp_type { + DXIL_PROG_SIG_COMP_TYPE_UNKNOWN = 0, + DXIL_PROG_SIG_COMP_TYPE_UINT32 = 1, + DXIL_PROG_SIG_COMP_TYPE_SINT32 = 2, + DXIL_PROG_SIG_COMP_TYPE_FLOAT32 = 3, + DXIL_PROG_SIG_COMP_TYPE_UINT16 = 4, + DXIL_PROG_SIG_COMP_TYPE_SINT16 = 5, + DXIL_PROG_SIG_COMP_TYPE_FLOAT16 = 6, + DXIL_PROG_SIG_COMP_TYPE_UINT64 = 7, + DXIL_PROG_SIG_COMP_TYPE_SINT64 = 8, + DXIL_PROG_SIG_COMP_TYPE_FLOAT64 = 9, + DXIL_PROG_SIG_COMP_TYPE_COUNT +}; + + +enum dxil_sig_point_kind { + DXIL_SIG_POINT_VSIN, // Ordinary Vertex Shader input from Input Assembler + DXIL_SIG_POINT_VSOUT, // Ordinary Vertex Shader output that may feed Rasterizer + DXIL_SIG_POINT_PCIN, // Patch Constant function non-patch inputs + DXIL_SIG_POINT_HSIN, // Hull Shader function non-patch inputs + DXIL_SIG_POINT_HSCPIN, // Hull Shader patch inputs - Control Points + DXIL_SIG_POINT_HSCPOut, // Hull Shader function output - Control Point + DXIL_SIG_POINT_PCOUT, // Patch Constant function output - Patch Constant data passed to Domain Shader + DXIL_SIG_POINT_DSIN, // Domain Shader regular input - Patch Constant data plus system values + DXIL_SIG_POINT_DSCPIN, // Domain Shader patch input - Control Points + DXIL_SIG_POINT_DSOUT, // Domain Shader output - vertex data that may feed Rasterizer + DXIL_SIG_POINT_GSVIN, // Geometry Shader vertex input - qualified with primitive type + DXIL_SIG_POINT_GSIN, // Geometry Shader non-vertex inputs (system values) + DXIL_SIG_POINT_GSOUT, // Geometry Shader output - vertex data that may feed Rasterizer + DXIL_SIG_POINT_PSIN, // Pixel Shader input + DXIL_SIG_POINT_PSOUT, // Pixel Shader output + DXIL_SIG_POINT_CSIN, // Compute Shader input + DXIL_SIG_POINT_MSIN, // Mesh Shader input + DXIL_SIG_POINT_MSOUT, // Mesh Shader vertices output + DXIL_SIG_POINT_MSPOUT, // Mesh Shader primitives output + DXIL_SIG_POINT_ASIN, // Amplification Shader input + DXIL_SIG_POINT_INVALID +}; + +enum dxil_min_precision { + DXIL_MIN_PREC_DEFAULT = 0, + DXIL_MIN_PREC_FLOAT16 = 1, + DXIL_MIN_PREC_FLOAT2_8 = 2, + DXIL_MIN_PREC_RESERVED = 3, + DXIL_MIN_PREC_SINT16 = 4, + DXIL_MIN_PREC_UINT16 = 5, + DXIL_MIN_PREC_ANY16 = 0xf0, + DXIL_MIN_PREC_ANY10 = 0xf1 +}; + +enum dxil_semantic_interpret_kind { + DXIL_SEM_INTERP_NA, // Not Available + DXIL_SEM_INTERP_SV, // Normal System Value + DXIL_SEM_INTERP_SGV, // System Generated Value (sorted last) + DXIL_SEM_INTERP_ARB, // Treated as Arbitrary + DXIL_SEM_INTERP_NOT_IN_SIG, // Not included in signature (intrinsic access) + DXIL_SEM_INTERP_NOT_PACKED, // Included in signature, but does not contribute to packing + DXIL_SEM_INTERP_TARGET, // Special handling for SV_Target + DXIL_SEM_INTERP_TESSFACTOR, // Special handling for tessellation factors + DXIL_SEM_INTERP_SHADOW, // Shadow element must be added to a signature for compatibility + DXIL_SEM_INTERP_CLIPCULL, // Special packing rules for SV_ClipDistance or SV_CullDistance + DXIL_SEM_INTERP_INVALID +}; + +enum dxil_component_type { + DXIL_COMP_TYPE_INVALID = 0, + DXIL_COMP_TYPE_I1 = 1, + DXIL_COMP_TYPE_I16 = 2, + DXIL_COMP_TYPE_U16 = 3, + DXIL_COMP_TYPE_I32 = 4, + DXIL_COMP_TYPE_U32 = 5, + DXIL_COMP_TYPE_I64 = 6, + DXIL_COMP_TYPE_U64 = 7, + DXIL_COMP_TYPE_F16 = 8, + DXIL_COMP_TYPE_F32 = 9, + DXIL_COMP_TYPE_F64 = 10, + DXIL_COMP_TYPE_SNORMF16 = 11, + DXIL_COMP_TYPE_UNORMF16 = 12, + DXIL_COMP_TYPE_SNORMF32 = 13, + DXIL_COMP_TYPE_UNORMF32 = 14, + DXIL_COMP_TYPE_SNORMF64 = 15, + DXIL_COMP_TYPE_UNORMF64 = 16 +}; + +enum dxil_interpolation_mode { + DXIL_INTERP_UNDEFINED = 0, + DXIL_INTERP_CONSTANT = 1, + DXIL_INTERP_LINEAR = 2, + DXIL_INTERP_LINEAR_CENTROID = 3, + DXIL_INTERP_LINEAR_NOPERSPECTIVE = 4, + DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID = 5, + DXIL_INTERP_LINEAR_SAMPLE = 6, + DXIL_INTERP_LINEAR_NOPERSPECTIVE_SAMPLE = 7, + DXIL_INTERP_INVALID = 8 +}; + +enum overload_type { + DXIL_NONE, + DXIL_I16, + DXIL_I32, + DXIL_I64, + DXIL_F16, + DXIL_F32, + DXIL_F64, + DXIL_NUM_OVERLOADS +}; + +enum dxil_resource_class { + DXIL_RESOURCE_CLASS_SRV = 0, + DXIL_RESOURCE_CLASS_UAV = 1, + DXIL_RESOURCE_CLASS_CBV = 2, + DXIL_RESOURCE_CLASS_SAMPLER = 3 +}; + +enum dxil_resource_kind { + DXIL_RESOURCE_KIND_INVALID = 0, + DXIL_RESOURCE_KIND_TEXTURE1D = 1, + DXIL_RESOURCE_KIND_TEXTURE2D = 2, + DXIL_RESOURCE_KIND_TEXTURE2DMS = 3, + DXIL_RESOURCE_KIND_TEXTURE3D = 4, + DXIL_RESOURCE_KIND_TEXTURECUBE = 5, + DXIL_RESOURCE_KIND_TEXTURE1D_ARRAY = 6, + DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY = 7, + DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY = 8, + DXIL_RESOURCE_KIND_TEXTURECUBE_ARRAY = 9, + DXIL_RESOURCE_KIND_TYPED_BUFFER = 10, + DXIL_RESOURCE_KIND_RAW_BUFFER = 11, + DXIL_RESOURCE_KIND_STRUCTURED_BUFFER = 12, + DXIL_RESOURCE_KIND_CBUFFER = 13, + DXIL_RESOURCE_KIND_SAMPLER = 14, + DXIL_RESOURCE_KIND_TBUFFER = 15, +}; + +enum dxil_sampler_kind { + DXIL_SAMPLER_KIND_DEFAULT = 0, + DXIL_SAMPLER_KIND_COMPARISON = 1, + DXIL_SAMPLER_KIND_MONO = 2, + DXIL_SAMPLER_KIND_INVALID = 3, +}; + +enum dxil_attr_kind { + DXIL_ATTR_KIND_NONE = 0, + DXIL_ATTR_KIND_NO_DUPLICATE = 12, + DXIL_ATTR_KIND_NO_UNWIND = 18, + DXIL_ATTR_KIND_READ_NONE = 20, + DXIL_ATTR_KIND_READ_ONLY = 21, +}; + +enum dxil_input_primitive { + DXIL_INPUT_PRIMITIVE_UNDEFINED = 0, + DXIL_INPUT_PRIMITIVE_POINT = 1, + DXIL_INPUT_PRIMITIVE_LINE = 2, + DXIL_INPUT_PRIMITIVE_TRIANGLE = 3, + DXIL_INPUT_PRIMITIVE_LINES_ADJENCY = 6, + DXIL_INPUT_PRIMITIVE_TRIANGLES_ADJENCY = 7, +}; + +enum dxil_primitive_topology { + DXIL_PRIMITIVE_TOPOLOGY_UNDEFINED = 0, + DXIL_PRIMITIVE_TOPOLOGY_POINT_LIST = 1, + DXIL_PRIMITIVE_TOPOLOGY_LINE_LIST = 2, + DXIL_PRIMITIVE_TOPOLOGY_LINE_STRIP = 3, + DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 4, + DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 5, +}; + +enum dxil_shader_tag { + DXIL_SHADER_TAG_FLAGS = 0, + DXIL_SHADER_TAG_GS_STATE = 1, + DXIL_SHADER_TAG_DS_STATE = 2, + DXIL_SHADER_TAG_HS_STATE = 3, + DXIL_SHADER_TAG_NUM_THREADS = 4, +}; + +enum dxil_barrier_mode { + DXIL_BARRIER_MODE_SYNC_THREAD_GROUP = 1, + DXIL_BARRIER_MODE_UAV_FENCE_GLOBAL = 2, + DXIL_BARRIER_MODE_UAV_FENCE_THREAD_GROUP = 4, + DXIL_BARRIER_MODE_GROUPSHARED_MEM_FENCE = 8, +}; + +enum dxil_address_space { + DXIL_AS_DEFAULT = 0, + DXIL_AS_DEVMEM = 1, + DXIL_AS_CBUF = 2, + DXIL_AS_GROUPSHARED = 3, +}; + +enum dxil_rmw_op { + DXIL_RMWOP_XCHG = 0, + DXIL_RMWOP_ADD = 1, + DXIL_RMWOP_SUB = 2, + DXIL_RMWOP_AND = 3, + DXIL_RMWOP_NAND = 4, + DXIL_RMWOP_OR = 5, + DXIL_RMWOP_XOR = 6, + DXIL_RMWOP_MAX = 7, + DXIL_RMWOP_MIN = 8, + DXIL_RMWOP_UMAX = 9, + DXIL_RMWOP_UMIN = 10, +}; + +enum dxil_atomic_ordering { + DXIL_ATOMIC_ORDERING_NOTATOMIC = 0, + DXIL_ATOMIC_ORDERING_UNORDERED = 1, + DXIL_ATOMIC_ORDERING_MONOTONIC = 2, + DXIL_ATOMIC_ORDERING_ACQUIRE = 3, + DXIL_ATOMIC_ORDERING_RELEASE = 4, + DXIL_ATOMIC_ORDERING_ACQREL = 5, + DXIL_ATOMIC_ORDERING_SEQCST = 6, +}; + +enum dxil_sync_scope { + DXIL_SYNC_SCOPE_SINGLETHREAD = 0, + DXIL_SYNC_SCOPE_CROSSTHREAD = 1, +}; + +#ifdef __cplusplus +extern "C" { +#endif + +enum dxil_component_type dxil_get_comp_type(const struct glsl_type *type); + +enum dxil_prog_sig_comp_type dxil_get_prog_sig_comp_type(const struct glsl_type *type); + +enum dxil_resource_kind dxil_get_resource_kind(const struct glsl_type *type); + +enum dxil_primitive_topology dxil_get_primitive_topology(unsigned topology); + +enum dxil_input_primitive dxil_get_input_primitive(unsigned primitive); + +const char *dxil_overload_suffix( enum overload_type overload); + +#ifdef __cplusplus +} +#endif + + +#endif // DXIL_ENUMS_H diff --git a/src/microsoft/compiler/dxil_function.c b/src/microsoft/compiler/dxil_function.c new file mode 100644 index 00000000000..ef2a06980b6 --- /dev/null +++ b/src/microsoft/compiler/dxil_function.c @@ -0,0 +1,236 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#include "dxil_function.h" +#include "dxil_module.h" + +#define MAX_FUNC_PARAMS 17 + +struct predefined_func_descr { + const char *base_name; + const char *retval_descr; + const char *param_descr; + enum dxil_attr_kind attr; +}; + +static struct predefined_func_descr predefined_funcs[] = { +{"dx.op.atomicBinOp", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.cbufferLoad", "O", "i@ii", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.cbufferLoadLegacy", "B", "i@i", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.createHandle", "@", "iciib", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.storeOutput", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND}, +{"dx.op.loadInput", "O", "iiici", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.tertiary", "O", "iOOO", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.threadId", "i", "ii", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.threadIdInGroup", "i", "ii", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.groupId", "i", "ii", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.unary", "O", "iO", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.unaryBits", "i", "iO", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.isSpecialFloat", "b", "iO", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.binary", "O", "iOO", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.bufferStore", "v", "i@iiiiiic", DXIL_ATTR_KIND_NONE}, +{"dx.op.bufferLoad", "R", "i@ii", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.attributeAtVertex", "O", "iiicc", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.sample", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.sampleBias", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.sampleLevel", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.sampleGrad", "R", "i@@ffffiiifffffff", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.sampleCmp", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.sampleCmpLevelZero", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.textureLoad", "R", "i@iiiiiii", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.discard", "v", "ib", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.emitStream", "v", "ic", DXIL_ATTR_KIND_NONE}, +{"dx.op.cutStream", "v", "ic", DXIL_ATTR_KIND_NONE}, +{"dx.op.getDimensions", "D", "i@i", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.calculateLOD", "f", "i@@fffb", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.barrier", "v", "ii", DXIL_ATTR_KIND_NO_DUPLICATE}, +{"dx.op.atomicCompareExchange", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.textureStore", "v", "i@iiiOOOOc", DXIL_ATTR_KIND_NONE}, +{"dx.op.primitiveID", "i", "i", DXIL_ATTR_KIND_READ_NONE}, +{"dx.op.legacyF16ToF32", "f", "ii", DXIL_ATTR_KIND_READ_ONLY}, +{"dx.op.legacyF32ToF16", "i", "if", DXIL_ATTR_KIND_READ_ONLY}, +}; + +struct func_descr { + const char *name; + enum overload_type overload; +}; + +struct func_rb_node { + struct rb_node node; + const struct dxil_func *func; + struct func_descr descr; +}; + +static inline +const struct func_rb_node * +func_rb_node(const struct rb_node *n) +{ + return (const struct func_rb_node *)n; +} + +static int +func_compare_to_name_and_overload(const struct rb_node *node, const void *data) +{ + const struct func_descr *descr = (const struct func_descr *)data; + const struct func_rb_node *f = func_rb_node(node); + if (f->descr.overload < descr->overload) + return -1; + if (f->descr.overload > descr->overload) + return 1; + + return strcmp(f->descr.name, descr->name); +} + +static const struct dxil_func * +allocate_function_from_predefined(struct dxil_module *mod, + const char *name, + enum overload_type overload) +{ + for (unsigned i = 0; i < ARRAYSIZE(predefined_funcs); ++i) { + if (!strcmp(predefined_funcs[i].base_name, name)) { + return dxil_alloc_func(mod, name, overload, + predefined_funcs[i].retval_descr, + predefined_funcs[i].param_descr, + predefined_funcs[i].attr); + } + } + return false; +} + +const struct dxil_func * +dxil_get_function(struct dxil_module *mod, + const char *name, enum overload_type overload) +{ + struct func_descr descr = { name, overload }; + const struct rb_node *node = rb_tree_search(mod->functions, &descr, + func_compare_to_name_and_overload); + if (node) + return func_rb_node(node)->func; + + return allocate_function_from_predefined(mod, name, overload); +} + +static int func_compare_name(const struct rb_node *lhs, const struct rb_node *rhs) +{ + const struct func_rb_node *node = func_rb_node(rhs); + return func_compare_to_name_and_overload(lhs, &node->descr); +} + +static void +dxil_add_function(struct rb_tree *functions, const struct dxil_func *func, + const char *name, enum overload_type overload) +{ + struct func_rb_node *f = rzalloc(functions, struct func_rb_node); + f->func = func; + f->descr.name = name; + f->descr.overload = overload; + rb_tree_insert(functions, &f->node, func_compare_name); +} + +static const struct dxil_type * +get_type_from_string(struct dxil_module *mod, const char *param_descr, + enum overload_type overload, int *idx) +{ + assert(param_descr); + char type_id = param_descr[(*idx)++]; + assert(*idx <= (int)strlen(param_descr)); + + switch (type_id) { + case DXIL_FUNC_PARAM_INT64: return dxil_module_get_int_type(mod, 64); + case DXIL_FUNC_PARAM_INT32: return dxil_module_get_int_type(mod, 32); + case DXIL_FUNC_PARAM_INT16: return dxil_module_get_int_type(mod, 16); + case DXIL_FUNC_PARAM_INT8: return dxil_module_get_int_type(mod, 8); + case DXIL_FUNC_PARAM_BOOL: return dxil_module_get_int_type(mod, 1); + case DXIL_FUNC_PARAM_FLOAT64: return dxil_module_get_float_type(mod, 64); + case DXIL_FUNC_PARAM_FLOAT32: return dxil_module_get_float_type(mod, 32); + case DXIL_FUNC_PARAM_FLOAT16: return dxil_module_get_float_type(mod, 16); + case DXIL_FUNC_PARAM_HANDLE: return dxil_module_get_handle_type(mod); + case DXIL_FUNC_PARAM_VOID: return dxil_module_get_void_type(mod); + case DXIL_FUNC_PARAM_FROM_OVERLOAD: return dxil_get_overload_type(mod, overload); + case DXIL_FUNC_PARAM_RESRET: return dxil_module_get_resret_type(mod, overload); + case DXIL_FUNC_PARAM_DIM: return dxil_module_get_dimret_type(mod); + case DXIL_FUNC_PARAM_CBUF_RET: return dxil_module_get_cbuf_ret_type(mod, overload); + case DXIL_FUNC_PARAM_POINTER: { + const struct dxil_type *target = get_type_from_string(mod, param_descr, overload, idx); + return dxil_module_get_pointer_type(mod, target); + } + default: + assert(0 && "unknown type identifier"); + } + return NULL; +} + +const struct dxil_func * +dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name, + enum overload_type overload, + const struct dxil_type *retval_type, + const char *param_descr, + enum dxil_attr_kind attr) +{ + assert(param_descr); + const struct dxil_type *arg_types[MAX_FUNC_PARAMS]; + + int index = 0; + unsigned num_params = 0; + + while (param_descr[num_params]) { + const struct dxil_type *t = get_type_from_string(mod, param_descr, overload, &index); + if (!t) + return false; + assert(num_params < MAX_FUNC_PARAMS); + arg_types[num_params++] = t; + } + + const struct dxil_type *func_type = + dxil_module_add_function_type(mod, retval_type, + arg_types, num_params); + if (!func_type) { + fprintf(stderr, "%s: Func type allocation failed\n", __func__); + return false; + } + + char full_name[100]; + snprintf(full_name, sizeof (full_name), "%s%s%s", name, + overload == DXIL_NONE ? "" : ".", dxil_overload_suffix(overload)); + const struct dxil_func *func = dxil_add_function_decl(mod, full_name, func_type, attr); + + if (func) + dxil_add_function(mod->functions, func, name, overload); + + return func; +} + +const struct dxil_func * +dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload, + const char *retval_type_descr, + const char *param_descr, enum dxil_attr_kind attr) +{ + + int index = 0; + const struct dxil_type *retval_type = get_type_from_string(mod, retval_type_descr, overload, &index); + assert(retval_type_descr[index] == 0); + + return dxil_alloc_func_with_rettype(mod, name, overload, retval_type, + param_descr, attr); +} diff --git a/src/microsoft/compiler/dxil_function.h b/src/microsoft/compiler/dxil_function.h new file mode 100644 index 00000000000..c615ab3e818 --- /dev/null +++ b/src/microsoft/compiler/dxil_function.h @@ -0,0 +1,92 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#ifndef DXIL_FUNCTION_H +#define DXIL_FUNCTION_H + +#define DXIL_FUNC_PARAM_INT64 'l' +#define DXIL_FUNC_PARAM_INT32 'i' +#define DXIL_FUNC_PARAM_INT16 'h' +#define DXIL_FUNC_PARAM_INT8 'c' +#define DXIL_FUNC_PARAM_BOOL 'b' + +#define DXIL_FUNC_PARAM_FLOAT64 'g' +#define DXIL_FUNC_PARAM_FLOAT32 'f' +#define DXIL_FUNC_PARAM_FLOAT16 'e' +#define DXIL_FUNC_PARAM_HANDLE '@' +#define DXIL_FUNC_PARAM_POINTER '*' +#define DXIL_FUNC_PARAM_VOID 'v' +#define DXIL_FUNC_PARAM_FROM_OVERLOAD 'O' +#define DXIL_FUNC_PARAM_RESRET 'R' +#define DXIL_FUNC_PARAM_CBUF_RET 'B' +#define DXIL_FUNC_PARAM_DIM 'D' + +#include "dxil_module.h" +#include "util/rb_tree.h" + +const char *dxil_overload_suffix( enum overload_type overload); + +const struct dxil_type * +dxil_get_overload_type(struct dxil_module *mod, enum overload_type overload); + +/* These functions implement a generic method for declaring functions + * The input parameters types are given as a string using the characters + * given above as identifyer for the types. Only scalars and pointers to + * scalars are implemented at this point. + * + * Examples: + * + * Call: dxil_alloc_func(mod, "storeData.f32", "v", "icf"); + * Result function: void storeData.f32(int32, int8, float32) + * + * Call: dxil_alloc_func(mod, "storeData.f32", "e", "*icf"); + * Result function: float16 storeData.f32(int32 *, int8, float32) + * + * Call: dxil_alloc_func(mod, "storeData.f32", "*h", "b*f"); + * Result function: float16 storeData.f32(bool *, float32 *) + * + */ + +const struct dxil_func * +dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload, + const char *retval_type_descr, const char *param_descr, enum dxil_attr_kind attr); + +/* For specifically constructed return types one can also create the return type + * seperately and pass it as paramaer + */ +const struct dxil_func * +dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name, enum overload_type overload, + const struct dxil_type *retval_type, const char *param_descr, + enum dxil_attr_kind attr); + +/* This call should be the usual entry point to allocate a new function type. + * 'name' must either be in the list of predefined functions, or a function + * with 'name' and 'overload' must already be allocated by using one of the above + * function calls. The allocated functions are searched for by using an rb_tree, so + * the search complexity should be O(log(n)). + */ +const struct dxil_func * +dxil_get_function(struct dxil_module *mod, const char *name, + enum overload_type overload); + +#endif // DXIL_FUNCTION_H diff --git a/src/microsoft/compiler/dxil_internal.h b/src/microsoft/compiler/dxil_internal.h new file mode 100644 index 00000000000..1c10e4fca0b --- /dev/null +++ b/src/microsoft/compiler/dxil_internal.h @@ -0,0 +1,300 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#ifndef DXIL_INTERNAL_H +#define DXIL_INTERNAL_H + +#include "dxil_module.h" + +#include "util/list.h" + +#include + +// Malloc.h defines a macro for alloca. Let's at least make sure that all includers +// of this header have the same definition of alloca. +#include + +struct dxil_type_list { + struct dxil_type **types; + size_t num_types; +}; + +struct dxil_type { + enum type_type { + TYPE_VOID, + TYPE_INTEGER, + TYPE_FLOAT, + TYPE_POINTER, + TYPE_STRUCT, + TYPE_ARRAY, + TYPE_VECTOR, + TYPE_FUNCTION + } type; + + union { + unsigned int_bits; + unsigned float_bits; + const struct dxil_type *ptr_target_type; + struct { + const char *name; + struct dxil_type_list elem; + } struct_def; + struct { + const struct dxil_type *ret_type; + struct dxil_type_list args; + } function_def; + struct { + const struct dxil_type *elem_type; + size_t num_elems; + } array_or_vector_def; + }; + + struct list_head head; + unsigned id; +}; + +struct dxil_value { + int id; + const struct dxil_type *type; +}; + +struct dxil_gvar { + const char *name; + const struct dxil_type *type; + bool constant; + enum dxil_address_space as; + int align; + + const struct dxil_value *initializer; + struct dxil_value value; + struct list_head head; +}; + +struct dxil_func { + char *name; + const struct dxil_type *type; + bool decl; + unsigned attr_set; + + struct dxil_value value; + struct list_head head; +}; + +struct dxil_attrib { + enum { + DXIL_ATTR_ENUM + } type; + + union { + enum dxil_attr_kind kind; + }; +}; + +struct attrib_set { + struct dxil_attrib attrs[2]; + unsigned num_attrs; + struct list_head head; +}; + +struct dxil_instr_binop { + enum dxil_bin_opcode opcode; + const struct dxil_value *operands[2]; + enum dxil_opt_flags flags; +}; + +struct dxil_instr_cmp { + enum dxil_cmp_pred pred; + const struct dxil_value *operands[2]; +}; + +struct dxil_instr_select { + const struct dxil_value *operands[3]; +}; + +struct dxil_instr_cast { + enum dxil_cast_opcode opcode; + const struct dxil_type *type; + const struct dxil_value *value; +}; + +struct dxil_instr_call { + const struct dxil_func *func; + struct dxil_value **args; + size_t num_args; +}; + +struct dxil_instr_ret { + struct dxil_value *value; +}; + +struct dxil_instr_extractval { + const struct dxil_value *src; + const struct dxil_type *type; + unsigned int idx; +}; + +struct dxil_instr_br { + const struct dxil_value *cond; + unsigned succ[2]; +}; + +struct dxil_instr_phi { + const struct dxil_type *type; + struct dxil_phi_src { + const struct dxil_value *value; + unsigned block; + } incoming[127]; + size_t num_incoming; +}; + +struct dxil_instr_alloca { + const struct dxil_type *alloc_type; + const struct dxil_type *size_type; + const struct dxil_value *size; + unsigned align; +}; + +struct dxil_instr_gep { + bool inbounds; + const struct dxil_type *source_elem_type; + struct dxil_value **operands; + size_t num_operands; +}; + +struct dxil_instr_load { + const struct dxil_value *ptr; + const struct dxil_type *type; + unsigned align; + bool is_volatile; +}; + +struct dxil_instr_store { + const struct dxil_value *value, *ptr; + unsigned align; + bool is_volatile; +}; + +struct dxil_instr_atomicrmw { + const struct dxil_value *value, *ptr; + enum dxil_rmw_op op; + bool is_volatile; + enum dxil_atomic_ordering ordering; + enum dxil_sync_scope syncscope; +}; + +struct dxil_instr_cmpxchg { + const struct dxil_value *cmpval, *newval, *ptr; + bool is_volatile; + enum dxil_atomic_ordering ordering; + enum dxil_sync_scope syncscope; +}; + +struct dxil_instr { + enum instr_type { + INSTR_BINOP, + INSTR_CMP, + INSTR_SELECT, + INSTR_CAST, + INSTR_BR, + INSTR_PHI, + INSTR_CALL, + INSTR_RET, + INSTR_EXTRACTVAL, + INSTR_ALLOCA, + INSTR_GEP, + INSTR_LOAD, + INSTR_STORE, + INSTR_ATOMICRMW, + INSTR_CMPXCHG, + } type; + + union { + struct dxil_instr_binop binop; + struct dxil_instr_cmp cmp; + struct dxil_instr_select select; + struct dxil_instr_cast cast; + struct dxil_instr_call call; + struct dxil_instr_ret ret; + struct dxil_instr_extractval extractval; + struct dxil_instr_phi phi; + struct dxil_instr_br br; + struct dxil_instr_alloca alloca; + struct dxil_instr_gep gep; + struct dxil_instr_load load; + struct dxil_instr_store store; + struct dxil_instr_atomicrmw atomicrmw; + struct dxil_instr_cmpxchg cmpxchg; + }; + + bool has_value; + struct dxil_value value; + + struct list_head head; +}; + +struct dxil_const { + struct dxil_value value; + + bool undef; + union { + intmax_t int_value; + double float_value; + const struct dxil_value **array_values; + }; + + struct list_head head; +}; + +struct dxil_mdnode { + enum mdnode_type { + MD_STRING, + MD_VALUE, + MD_NODE + } type; + + union { + char *string; + + struct { + const struct dxil_type *type; + const struct dxil_value *value; + } value; + + struct { + struct dxil_mdnode **subnodes; + size_t num_subnodes; + } node; + }; + + struct list_head head; + unsigned id; +}; + +struct dxil_named_node { + char *name; + struct dxil_mdnode **subnodes; + size_t num_subnodes; + struct list_head head; +}; + +#endif // DXIL_INTERNAL_H diff --git a/src/microsoft/compiler/dxil_module.c b/src/microsoft/compiler/dxil_module.c new file mode 100644 index 00000000000..f8d3a9054a1 --- /dev/null +++ b/src/microsoft/compiler/dxil_module.c @@ -0,0 +1,3320 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#include "dxil_module.h" +#include "dxil_internal.h" + +#include "util/macros.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/rb_tree.h" + +#include + +void +dxil_module_init(struct dxil_module *m, void *ralloc_ctx) +{ + assert(ralloc_ctx); + + memset(m, 0, sizeof(struct dxil_module)); + m->ralloc_ctx = ralloc_ctx; + + dxil_buffer_init(&m->buf, 2); + memset(&m->feats, 0, sizeof(m->feats)); + + list_inithead(&m->type_list); + list_inithead(&m->func_list); + list_inithead(&m->attr_set_list); + list_inithead(&m->gvar_list); + list_inithead(&m->const_list); + list_inithead(&m->instr_list); + list_inithead(&m->mdnode_list); + list_inithead(&m->md_named_node_list); + + m->functions = rzalloc(ralloc_ctx, struct rb_tree); + rb_tree_init(m->functions); + + m->curr_block = 0; +} + +void +dxil_module_release(struct dxil_module *m) +{ + dxil_buffer_finish(&m->buf); +} + +bool +emit_bits64(struct dxil_buffer *b, uint64_t data, unsigned width) +{ + if (data > UINT32_MAX) { + assert(width > 32); + return dxil_buffer_emit_bits(b, (uint32_t)(data & UINT32_MAX), width) && + dxil_buffer_emit_bits(b, (uint32_t)(data >> 32), width - 32); + } else + return dxil_buffer_emit_bits(b, (uint32_t)data, width); +} + +/* See the LLVM documentation for details about what these are all about: + * https://www.llvm.org/docs/BitCodeFormat.html#abbreviation-ids + */ +enum dxil_fixed_abbrev { + DXIL_END_BLOCK = 0, + DXIL_ENTER_SUBBLOCK = 1, + DXIL_DEFINE_ABBREV = 2, + DXIL_UNABBREV_RECORD = 3, + DXIL_FIRST_APPLICATION_ABBREV = 4 +}; + +static bool +enter_subblock(struct dxil_module *m, unsigned id, unsigned abbrev_width) +{ + assert(m->num_blocks < ARRAY_SIZE(m->blocks)); + m->blocks[m->num_blocks].abbrev_width = m->buf.abbrev_width; + + if (!dxil_buffer_emit_abbrev_id(&m->buf, DXIL_ENTER_SUBBLOCK) || + !dxil_buffer_emit_vbr_bits(&m->buf, id, 8) || + !dxil_buffer_emit_vbr_bits(&m->buf, abbrev_width, 4) || + !dxil_buffer_align(&m->buf)) + return false; + + m->buf.abbrev_width = abbrev_width; + m->blocks[m->num_blocks++].offset = blob_reserve_uint32(&m->buf.blob); + return true; +} + +static bool +exit_block(struct dxil_module *m) +{ + assert(m->num_blocks > 0); + assert(m->num_blocks < ARRAY_SIZE(m->blocks)); + + if (!dxil_buffer_emit_abbrev_id(&m->buf, DXIL_END_BLOCK) || + !dxil_buffer_align(&m->buf)) + return false; + + intptr_t size_offset = m->blocks[m->num_blocks - 1].offset; + uint32_t size = (m->buf.blob.size - size_offset - 1) / sizeof(uint32_t); + if (!blob_overwrite_uint32(&m->buf.blob, size_offset, size)) + return false; + + m->num_blocks--; + m->buf.abbrev_width = m->blocks[m->num_blocks].abbrev_width; + return true; +} + +static bool +emit_record_no_abbrev(struct dxil_buffer *b, unsigned code, + const uint64_t *data, size_t size) +{ + if (!dxil_buffer_emit_abbrev_id(b, DXIL_UNABBREV_RECORD) || + !dxil_buffer_emit_vbr_bits(b, code, 6) || + !dxil_buffer_emit_vbr_bits(b, size, 6)) + return false; + + for (size_t i = 0; i < size; ++i) + if (!dxil_buffer_emit_vbr_bits(b, data[i], 6)) + return false; + + return true; +} + +static bool +emit_record(struct dxil_module *m, unsigned code, + const uint64_t *data, size_t size) +{ + return emit_record_no_abbrev(&m->buf, code, data, size); +} + +static bool +emit_record_int(struct dxil_module *m, unsigned code, int value) +{ + uint64_t data = value; + return emit_record(m, code, &data, 1); +} + +static bool +is_char6(char ch) +{ + if ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9')) + return true; + + switch (ch) { + case '.': + case '_': + return true; + + default: + return false; + } +} + +static bool +is_char6_string(const char *str) +{ + while (*str != '\0') { + if (!is_char6(*str++)) + return false; + } + return true; +} + +static bool +is_char7_string(const char *str) +{ + while (*str != '\0') { + if (*str++ >= 128) + return false; + } + return true; +} + +static unsigned +encode_char6(char ch) +{ + const int letters = 'z' - 'a' + 1; + + if (ch >= 'a' && ch <= 'z') + return ch - 'a'; + else if (ch >= 'A' && ch <= 'Z') + return letters + ch - 'A'; + else if (ch >= '0' && ch <= '9') + return 2 * letters + ch - '0'; + + switch (ch) { + case '.': return 62; + case '_': return 63; + default: + unreachable("invalid char6-character"); + } +} + +static bool +emit_fixed(struct dxil_buffer *b, uint64_t data, unsigned width) +{ + if (!width) + return true; + + return emit_bits64(b, data, width); +} + +static bool +emit_vbr(struct dxil_buffer *b, uint64_t data, unsigned width) +{ + if (!width) + return true; + + return dxil_buffer_emit_vbr_bits(b, data, width); +} + +static bool +emit_char6(struct dxil_buffer *b, uint64_t data) +{ + return dxil_buffer_emit_bits(b, encode_char6((char)data), 6); +} + +struct dxil_abbrev { + struct { + enum { + DXIL_OP_LITERAL = 0, + DXIL_OP_FIXED = 1, + DXIL_OP_VBR = 2, + DXIL_OP_ARRAY = 3, + DXIL_OP_CHAR6 = 4, + DXIL_OP_BLOB = 5 + } type; + union { + uint64_t value; + uint64_t encoding_data; + }; + } operands[7]; + size_t num_operands; +}; + +static bool +emit_record_abbrev(struct dxil_buffer *b, + unsigned abbrev, const struct dxil_abbrev *a, + const uint64_t *data, size_t size) +{ + assert(abbrev >= DXIL_FIRST_APPLICATION_ABBREV); + + if (!dxil_buffer_emit_abbrev_id(b, abbrev)) + return false; + + size_t curr_data = 0; + for (int i = 0; i < a->num_operands; ++i) { + switch (a->operands[i].type) { + case DXIL_OP_LITERAL: + assert(curr_data < size); + assert(data[curr_data] == a->operands[i].value); + curr_data++; + /* literals are no-ops, because their value is defined in the + abbrev-definition already */ + break; + + case DXIL_OP_FIXED: + assert(curr_data < size); + if (!emit_fixed(b, data[curr_data++], a->operands[i].encoding_data)) + return false; + break; + + case DXIL_OP_VBR: + assert(curr_data < size); + if (!emit_vbr(b, data[curr_data++], a->operands[i].encoding_data)) + return false; + break; + + case DXIL_OP_ARRAY: + assert(i == a->num_operands - 2); /* arrays should always be second to last */ + + if (!dxil_buffer_emit_vbr_bits(b, size - curr_data, 6)) + return false; + + switch (a->operands[i + 1].type) { + case DXIL_OP_FIXED: + while (curr_data < size) + if (!emit_fixed(b, data[curr_data++], a->operands[i + 1].encoding_data)) + return false; + break; + + case DXIL_OP_VBR: + while (curr_data < size) + if (!emit_vbr(b, data[curr_data++], a->operands[i + 1].encoding_data)) + return false; + break; + + case DXIL_OP_CHAR6: + while (curr_data < size) + if (!emit_char6(b, data[curr_data++])) + return false; + break; + + default: + unreachable("unexpected operand type"); + } + return true; /* we're done */ + + case DXIL_OP_CHAR6: + assert(curr_data < size); + if (!emit_char6(b, data[curr_data++])) + return false; + break; + + case DXIL_OP_BLOB: + unreachable("HALP, unplement!"); + + default: + unreachable("unexpected operand type"); + } + } + + assert(curr_data == size); + return true; +} + + +static struct dxil_type * +create_type(struct dxil_module *m, enum type_type type) +{ + struct dxil_type *ret = rzalloc_size(m->ralloc_ctx, + sizeof(struct dxil_type)); + if (ret) { + ret->type = type; + ret->id = list_length(&m->type_list); + list_addtail(&ret->head, &m->type_list); + } + return ret; +} + +static bool +types_equal(const struct dxil_type *lhs, const struct dxil_type *rhs); + +static bool +type_list_equal(const struct dxil_type_list *lhs, + const struct dxil_type_list *rhs) +{ + if (lhs->num_types != rhs->num_types) + return false; + for (unsigned i = 0; i < lhs->num_types; ++i) + if (!types_equal(lhs->types[i], rhs->types[i])) + return false; + return true; +} + +static bool +types_equal(const struct dxil_type *lhs, const struct dxil_type *rhs) +{ + if (lhs == rhs) + return true; + + /* Below we only assert that different type pointers really define different types + * Since this function is only called in asserts, it is not needed to put the code + * into a #ifdef NDEBUG statement */ + if (lhs->type != rhs->type) + return false; + + bool retval = false; + switch (lhs->type) { + case TYPE_VOID: + retval = true; + break; + case TYPE_FLOAT: + retval = lhs->float_bits == rhs->float_bits; + break; + case TYPE_INTEGER: + retval = lhs->int_bits == rhs->int_bits; + break; + case TYPE_POINTER: + retval = types_equal(lhs->ptr_target_type, rhs->ptr_target_type); + break; + case TYPE_ARRAY: + case TYPE_VECTOR: + retval = (lhs->array_or_vector_def.num_elems == rhs->array_or_vector_def.num_elems) && + types_equal(lhs->array_or_vector_def.elem_type, + rhs->array_or_vector_def.elem_type); + break; + case TYPE_FUNCTION: + if (!types_equal(lhs->function_def.ret_type, + rhs->function_def.ret_type)) + return false; + retval = type_list_equal(&lhs->function_def.args, &rhs->function_def.args); + break; + case TYPE_STRUCT: + retval = type_list_equal(&lhs->struct_def.elem, &rhs->struct_def.elem); + } + assert(!retval && "Types are equal in structure but not as pointers"); + return retval; +} + +bool +dxil_value_type_equal_to(const struct dxil_value *value, + const struct dxil_type *rhs) +{ + return types_equal(value->type, rhs); +} + +nir_alu_type +dxil_type_to_nir_type(const struct dxil_type *type) +{ + assert(type); + switch (type->type) { + case TYPE_INTEGER: + return type->int_bits == 1 ? nir_type_bool : nir_type_int; + case TYPE_FLOAT: + return nir_type_float; + default: + unreachable("Unexpected type in dxil_type_to_nir_type"); + } +} + +bool +dxil_value_type_bitsize_equal_to(const struct dxil_value *value, unsigned bitsize) +{ + switch (value->type->type) { + case TYPE_INTEGER: + return value->type->int_bits == bitsize; + case TYPE_FLOAT: + return value->type->float_bits == bitsize; + default: + return false; + } +} + +const struct dxil_type * +dxil_value_get_type(const struct dxil_value *value) +{ + return value->type; +} + +const struct dxil_type * +dxil_module_get_void_type(struct dxil_module *m) +{ + if (!m->void_type) + m->void_type = create_type(m, TYPE_VOID); + return m->void_type; +} + +static const struct dxil_type * +create_int_type(struct dxil_module *m, unsigned bit_size) +{ + struct dxil_type *type = create_type(m, TYPE_INTEGER); + if (type) + type->int_bits = bit_size; + return type; +} + +static const struct dxil_type * +get_int1_type(struct dxil_module *m) +{ + if (!m->int1_type) + m->int1_type = create_int_type(m, 1); + return m->int1_type; +} + +static const struct dxil_type * +get_int8_type(struct dxil_module *m) +{ + if (!m->int8_type) + m->int8_type = create_int_type(m, 8); + return m->int8_type; +} + +static const struct dxil_type * +get_int16_type(struct dxil_module *m) +{ + if (!m->int16_type) + m->int16_type = create_int_type(m, 16); + return m->int16_type; +} + +static const struct dxil_type * +get_int32_type(struct dxil_module *m) +{ + if (!m->int32_type) + m->int32_type = create_int_type(m, 32); + return m->int32_type; +} + +static const struct dxil_type * +get_int64_type(struct dxil_module *m) +{ + if (!m->int64_type) + m->int64_type = create_int_type(m, 64); + return m->int64_type; +} + +static const struct dxil_type * +create_float_type(struct dxil_module *m, unsigned bit_size) +{ + struct dxil_type *type = create_type(m, TYPE_FLOAT); + if (type) + type->float_bits = bit_size; + return type; +} + +const struct dxil_type * +dxil_module_get_int_type(struct dxil_module *m, unsigned bit_size) +{ + switch (bit_size) { + case 1: return get_int1_type(m); + case 8: return get_int8_type(m); + case 16: return get_int16_type(m); + case 32: return get_int32_type(m); + case 64: return get_int64_type(m); + default: + unreachable("unsupported bit-width"); + } +} + +static const struct dxil_type * +get_float16_type(struct dxil_module *m) +{ + if (!m->float16_type) + m->float16_type = create_float_type(m, 16); + return m->float16_type; +} + +static const struct dxil_type * +get_float32_type(struct dxil_module *m) +{ + if (!m->float32_type) + m->float32_type = create_float_type(m, 32); + return m->float32_type; +} + +static const struct dxil_type * +get_float64_type(struct dxil_module *m) +{ + if (!m->float64_type) + m->float64_type = create_float_type(m, 64); + return m->float64_type; +} + +const struct dxil_type * +dxil_module_get_float_type(struct dxil_module *m, unsigned bit_size) +{ + switch (bit_size) { + case 16: return get_float16_type(m); + case 32: return get_float32_type(m); + case 64: return get_float64_type(m); + default: + unreachable("unsupported bit-width"); + } + return get_float32_type(m); +} + +const struct dxil_type * +dxil_module_get_pointer_type(struct dxil_module *m, + const struct dxil_type *target) +{ + struct dxil_type *type; + LIST_FOR_EACH_ENTRY(type, &m->type_list, head) { + if (type->type == TYPE_POINTER && + type->ptr_target_type == target) + return type; + } + + type = create_type(m, TYPE_POINTER); + if (type) + type->ptr_target_type = target; + return type; +} + +const struct dxil_type * +dxil_module_get_struct_type(struct dxil_module *m, + const char *name, + const struct dxil_type **elem_types, + size_t num_elem_types) +{ + assert(!name || strlen(name) > 0); + + struct dxil_type *type; + LIST_FOR_EACH_ENTRY(type, &m->type_list, head) { + if (type->type != TYPE_STRUCT) + continue; + + if ((name == NULL) != (type->struct_def.name == NULL)) + continue; + + if (name && strcmp(type->struct_def.name, name)) + continue; + + if (type->struct_def.elem.num_types == num_elem_types && + !memcmp(type->struct_def.elem.types, elem_types, + sizeof(struct dxil_type *) * num_elem_types)) + return type; + } + + type = create_type(m, TYPE_STRUCT); + if (type) { + if (name) { + type->struct_def.name = ralloc_strdup(type, name); + if (!type->struct_def.name) + return NULL; + } else + type->struct_def.name = NULL; + + type->struct_def.elem.types = ralloc_array(type, struct dxil_type *, + num_elem_types); + if (!type->struct_def.elem.types) + return NULL; + + memcpy(type->struct_def.elem.types, elem_types, + sizeof(struct dxil_type *) * num_elem_types); + type->struct_def.elem.num_types = num_elem_types; + } + return type; +} + +const struct dxil_type * +dxil_module_get_array_type(struct dxil_module *m, + const struct dxil_type *elem_type, + size_t num_elems) +{ + struct dxil_type *type; + LIST_FOR_EACH_ENTRY(type, &m->type_list, head) { + if (type->type != TYPE_ARRAY) + continue; + + if (type->array_or_vector_def.elem_type == elem_type && + type->array_or_vector_def.num_elems == num_elems) + return type; + } + + type = create_type(m, TYPE_ARRAY); + if (type) { + type->array_or_vector_def.elem_type = elem_type; + type->array_or_vector_def.num_elems = num_elems; + } + return type; +} + +const struct dxil_type * +dxil_module_get_vector_type(struct dxil_module *m, + const struct dxil_type *elem_type, + size_t num_elems) +{ + struct dxil_type *type; + LIST_FOR_EACH_ENTRY(type, &m->type_list, head) { + if (type->type == TYPE_VECTOR && + type->array_or_vector_def.elem_type == elem_type && + type->array_or_vector_def.num_elems == num_elems) + return type; + } + + type = create_type(m, TYPE_VECTOR); + if (!type) + return NULL; + + type->array_or_vector_def.elem_type = elem_type; + type->array_or_vector_def.num_elems = num_elems; + return type; +} + +const struct dxil_type * +dxil_get_overload_type(struct dxil_module *mod, enum overload_type overload) +{ + switch (overload) { + case DXIL_I16: return get_int16_type(mod); + case DXIL_I32: return get_int32_type(mod); + case DXIL_I64: return get_int64_type(mod); + case DXIL_F32: return get_float32_type(mod); + case DXIL_F64: return get_float64_type(mod); + default: + unreachable("unexpected overload type"); + } +} + +const struct dxil_type * +dxil_module_get_handle_type(struct dxil_module *m) +{ + const struct dxil_type *int8_type = get_int8_type(m); + if (!int8_type) + return NULL; + + const struct dxil_type *ptr_type = dxil_module_get_pointer_type(m, int8_type); + if (!ptr_type) + return NULL; + + return dxil_module_get_struct_type(m, "dx.types.Handle", &ptr_type, 1); +} + +const struct dxil_type * +dxil_module_get_cbuf_ret_type(struct dxil_module *mod, enum overload_type overload) +{ + const struct dxil_type *overload_type = dxil_get_overload_type(mod, overload); + const struct dxil_type *fields[4] = { overload_type, overload_type, overload_type, overload_type }; + unsigned num_fields; + + char name[64]; + snprintf(name, sizeof(name), "dx.types.CBufRet.%s", dxil_overload_suffix(overload)); + + switch (overload) { + case DXIL_I32: + case DXIL_F32: + num_fields = 4; + break; + case DXIL_I64: + case DXIL_F64: + num_fields = 2; + break; + default: + unreachable("unexpected overload type"); + } + + return dxil_module_get_struct_type(mod, name, fields, num_fields); +} + +static const struct dxil_type * +dxil_module_get_type_from_comp_type(struct dxil_module *m, enum dxil_component_type comp_type) +{ + switch (comp_type) { + case DXIL_COMP_TYPE_U32: return get_int32_type(m); + case DXIL_COMP_TYPE_I32: return get_int32_type(m); + case DXIL_COMP_TYPE_F32: return get_float32_type(m); + case DXIL_COMP_TYPE_F64: return get_float64_type(m); + case DXIL_COMP_TYPE_U16: return get_int16_type(m); + case DXIL_COMP_TYPE_I16: return get_int16_type(m); + case DXIL_COMP_TYPE_U64: return get_int64_type(m); + case DXIL_COMP_TYPE_I64: return get_int64_type(m); + case DXIL_COMP_TYPE_I1: return get_int1_type(m); + + case DXIL_COMP_TYPE_F16: + default: + unreachable("unexpected component type"); + } +} + +static const char * +get_res_comp_type_name(enum dxil_component_type comp_type) +{ + switch (comp_type) { + case DXIL_COMP_TYPE_F64: return "double"; + case DXIL_COMP_TYPE_F32: return "float"; + case DXIL_COMP_TYPE_I32: return "int"; + case DXIL_COMP_TYPE_U32: return "uint"; + case DXIL_COMP_TYPE_I64: return "int64"; + case DXIL_COMP_TYPE_U64: return "uint64"; + default: + unreachable("unexpected resource component type"); + } +} + +static const char * +get_res_dimension_type_name(enum dxil_resource_kind kind) +{ + switch (kind) { + case DXIL_RESOURCE_KIND_TYPED_BUFFER: return "Buffer"; + case DXIL_RESOURCE_KIND_TEXTURE1D: return "Texture1D"; + case DXIL_RESOURCE_KIND_TEXTURE1D_ARRAY: return "Texture1DArray"; + case DXIL_RESOURCE_KIND_TEXTURE2D: return "Texture2D"; + case DXIL_RESOURCE_KIND_TEXTURE2DMS: return "Texture2DMS"; + case DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY: return "Texture2DArray"; + case DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY: return "Texture2DMSArray"; + case DXIL_RESOURCE_KIND_TEXTURE3D: return "Texture3D"; + case DXIL_RESOURCE_KIND_TEXTURECUBE: return "TextureCube"; + case DXIL_RESOURCE_KIND_TEXTURECUBE_ARRAY: return "TextureCubeArray"; + default: + unreachable("unexpected resource kind"); + } +} + +static const char * +get_res_ms_postfix(enum dxil_resource_kind kind) +{ + switch (kind) { + case DXIL_RESOURCE_KIND_TEXTURE2DMS: + case DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY: + return ", 0"; + + default: + return " "; + } +} +const struct dxil_type * +dxil_module_get_res_type(struct dxil_module *m, enum dxil_resource_kind kind, + enum dxil_component_type comp_type, bool readwrite) +{ + switch (kind) { + case DXIL_RESOURCE_KIND_TYPED_BUFFER: + case DXIL_RESOURCE_KIND_TEXTURE1D: + case DXIL_RESOURCE_KIND_TEXTURE1D_ARRAY: + case DXIL_RESOURCE_KIND_TEXTURE2D: + case DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY: + case DXIL_RESOURCE_KIND_TEXTURE2DMS: + case DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY: + case DXIL_RESOURCE_KIND_TEXTURE3D: + case DXIL_RESOURCE_KIND_TEXTURECUBE: + case DXIL_RESOURCE_KIND_TEXTURECUBE_ARRAY: + { + const struct dxil_type *int32_type = dxil_module_get_int_type(m, 32); + const struct dxil_type *component_type = dxil_module_get_type_from_comp_type(m, comp_type); + const struct dxil_type *vec_type = dxil_module_get_vector_type(m, component_type, 4); + char class_name[64] = { 0 }; + sprintf_s(class_name, 64, "class.%s%s%s>", + readwrite ? "RW" : "", + get_res_dimension_type_name(kind), + get_res_comp_type_name(comp_type), + get_res_ms_postfix(kind)); + return dxil_module_get_struct_type(m, class_name, &vec_type, 1); + } + + default: + unreachable("resource type not supported"); + } +} + +const struct dxil_type * +dxil_module_get_resret_type(struct dxil_module *m, enum overload_type overload) +{ + const struct dxil_type *overload_type = dxil_get_overload_type(m, overload); + const struct dxil_type *int32_type = dxil_module_get_int_type(m, 32); + const char *name; + if (!overload_type) + return NULL; + + const struct dxil_type *resret[] = + { overload_type, overload_type, overload_type, overload_type, int32_type }; + + switch (overload) { + case DXIL_I32: name = "dx.types.ResRet.i32"; break; + case DXIL_I64: name = "dx.types.ResRet.i64"; break; + case DXIL_F32: name = "dx.types.ResRet.f32"; break; + case DXIL_F64: name = "dx.types.ResRet.f64"; break; + default: + unreachable("unexpected overload type"); + } + + return dxil_module_get_struct_type(m, name, resret, 5); +} + +const struct dxil_type * +dxil_module_get_dimret_type(struct dxil_module *m) +{ + const struct dxil_type *int32_type = dxil_module_get_int_type(m, 32); + + const struct dxil_type *dimret[] = + { int32_type, int32_type, int32_type, int32_type }; + + return dxil_module_get_struct_type(m, "dx.types.Dimensions", dimret, 4); +} + +const struct dxil_type * +dxil_module_add_function_type(struct dxil_module *m, + const struct dxil_type *ret_type, + const struct dxil_type **arg_types, + size_t num_arg_types) +{ + struct dxil_type *type = create_type(m, TYPE_FUNCTION); + if (type) { + type->function_def.args.types = ralloc_array(type, + struct dxil_type *, + num_arg_types); + if (!type->function_def.args.types) + return NULL; + + memcpy(type->function_def.args.types, arg_types, + sizeof(struct dxil_type *) * num_arg_types); + type->function_def.args.num_types = num_arg_types; + type->function_def.ret_type = ret_type; + } + return type; +} + + +enum type_codes { + TYPE_CODE_NUMENTRY = 1, + TYPE_CODE_VOID = 2, + TYPE_CODE_FLOAT = 3, + TYPE_CODE_DOUBLE = 4, + TYPE_CODE_LABEL = 5, + TYPE_CODE_OPAQUE = 6, + TYPE_CODE_INTEGER = 7, + TYPE_CODE_POINTER = 8, + TYPE_CODE_FUNCTION_OLD = 9, + TYPE_CODE_HALF = 10, + TYPE_CODE_ARRAY = 11, + TYPE_CODE_VECTOR = 12, + TYPE_CODE_X86_FP80 = 13, + TYPE_CODE_FP128 = 14, + TYPE_CODE_PPC_FP128 = 15, + TYPE_CODE_METADATA = 16, + TYPE_CODE_X86_MMX = 17, + TYPE_CODE_STRUCT_ANON = 18, + TYPE_CODE_STRUCT_NAME = 19, + TYPE_CODE_STRUCT_NAMED = 20, + TYPE_CODE_FUNCTION = 21 +}; + +#define LITERAL(x) { DXIL_OP_LITERAL, (x) } +#define FIXED(x) { DXIL_OP_FIXED, (x) } +#define VBR(x) { DXIL_OP_VBR, (x) } +#define ARRAY { DXIL_OP_ARRAY, 0 } +#define CHAR6 { DXIL_OP_CHAR6, 0 } +#define BLOB { DXIL_OP_BLOB, 0 } + +#define TYPE_INDEX FIXED(32) + +enum type_table_abbrev_id { + TYPE_TABLE_ABBREV_POINTER, + TYPE_TABLE_ABBREV_FUNCTION, + TYPE_TABLE_ABBREV_STRUCT_ANON, + TYPE_TABLE_ABBREV_STRUCT_NAME, + TYPE_TABLE_ABBREV_STRUCT_NAMED, + TYPE_TABLE_ABBREV_ARRAY, + TYPE_TABLE_ABBREV_VECTOR, +}; + +static const struct dxil_abbrev +type_table_abbrevs[] = { + [TYPE_TABLE_ABBREV_POINTER] = { + { LITERAL(TYPE_CODE_POINTER), TYPE_INDEX, LITERAL(0) }, 3 + }, + [TYPE_TABLE_ABBREV_FUNCTION] = { + { LITERAL(TYPE_CODE_FUNCTION), FIXED(1), ARRAY, TYPE_INDEX }, 4 + }, + [TYPE_TABLE_ABBREV_STRUCT_ANON] = { + { LITERAL(TYPE_CODE_STRUCT_ANON), FIXED(1), ARRAY, TYPE_INDEX }, 4 + }, + [TYPE_TABLE_ABBREV_STRUCT_NAME] = { + { LITERAL(TYPE_CODE_STRUCT_NAME), ARRAY, CHAR6 }, 3 + }, + [TYPE_TABLE_ABBREV_STRUCT_NAMED] = { + { LITERAL(TYPE_CODE_STRUCT_NAMED), FIXED(1), ARRAY, TYPE_INDEX }, 4 + }, + [TYPE_TABLE_ABBREV_ARRAY] = { + { LITERAL(TYPE_CODE_ARRAY), VBR(8), TYPE_INDEX }, 3 + }, + [TYPE_TABLE_ABBREV_VECTOR] = { + { LITERAL(TYPE_CODE_VECTOR), VBR(8), TYPE_INDEX }, 3 + }, +}; + +static bool +emit_type_table_abbrev_record(struct dxil_module *m, + enum type_table_abbrev_id abbrev, + const uint64_t *data, size_t size) +{ + assert(abbrev < ARRAY_SIZE(type_table_abbrevs)); + return emit_record_abbrev(&m->buf, abbrev + DXIL_FIRST_APPLICATION_ABBREV, + type_table_abbrevs + abbrev, data, size); +} + +enum constant_code { + CST_CODE_SETTYPE = 1, + CST_CODE_NULL = 2, + CST_CODE_UNDEF = 3, + CST_CODE_INTEGER = 4, + CST_CODE_WIDE_INTEGER = 5, + CST_CODE_FLOAT = 6, + CST_CODE_AGGREGATE = 7, + CST_CODE_STRING = 8, + CST_CODE_CSTRING = 9, + CST_CODE_CE_BINOP = 10, + CST_CODE_CE_CAST = 11, + CST_CODE_CE_GEP = 12, + CST_CODE_CE_SELECT = 13, + CST_CODE_CE_EXTRACTELT = 14, + CST_CODE_CE_INSERTELT = 15, + CST_CODE_CE_SHUFFLEVEC = 16, + CST_CODE_CE_CMP = 17, + CST_CODE_INLINEASM_OLD = 18, + CST_CODE_CE_SHUFVEC_EX = 19, + CST_CODE_CE_INBOUNDS_GEP = 20, + CST_CODE_BLOCKADDRESS = 21, + CST_CODE_DATA = 22, + CST_CODE_INLINEASM = 23 +}; + +enum const_abbrev_id { + CONST_ABBREV_SETTYPE, + CONST_ABBREV_INTEGER, + CONST_ABBREV_CE_CAST, + CONST_ABBREV_NULL, +}; + +static const struct dxil_abbrev +const_abbrevs[] = { + [CONST_ABBREV_SETTYPE] = { { LITERAL(CST_CODE_SETTYPE), TYPE_INDEX }, 2 }, + [CONST_ABBREV_INTEGER] = { { LITERAL(CST_CODE_INTEGER), VBR(8) }, 2 }, + [CONST_ABBREV_CE_CAST] = { + { LITERAL(CST_CODE_CE_CAST), FIXED(4), TYPE_INDEX, VBR(8) }, 4 + }, + [CONST_ABBREV_NULL] = { { LITERAL(CST_CODE_NULL) }, 1 }, +}; + +static bool +emit_const_abbrev_record(struct dxil_module *m, enum const_abbrev_id abbrev, + const uint64_t *data, size_t size) +{ + assert(abbrev < ARRAY_SIZE(const_abbrevs)); + + return emit_record_abbrev(&m->buf, abbrev + DXIL_FIRST_APPLICATION_ABBREV, + const_abbrevs + abbrev, data, size); +} + +enum function_code { + FUNC_CODE_DECLAREBLOCKS = 1, + FUNC_CODE_INST_BINOP = 2, + FUNC_CODE_INST_CAST = 3, + FUNC_CODE_INST_GEP_OLD = 4, + FUNC_CODE_INST_SELECT = 5, + FUNC_CODE_INST_EXTRACTELT = 6, + FUNC_CODE_INST_INSERTELT = 7, + FUNC_CODE_INST_SHUFFLEVEC = 8, + FUNC_CODE_INST_CMP = 9, + FUNC_CODE_INST_RET = 10, + FUNC_CODE_INST_BR = 11, + FUNC_CODE_INST_SWITCH = 12, + FUNC_CODE_INST_INVOKE = 13, + /* 14: unused */ + FUNC_CODE_INST_UNREACHABLE = 15, + FUNC_CODE_INST_PHI = 16, + /* 17-18: unused */ + FUNC_CODE_INST_ALLOCA = 19, + FUNC_CODE_INST_LOAD = 20, + /* 21-22: unused */ + FUNC_CODE_INST_VAARG = 23, + FUNC_CODE_INST_STORE_OLD = 24, + /* 25: unused */ + FUNC_CODE_INST_EXTRACTVAL = 26, + FUNC_CODE_INST_INSERTVAL = 27, + FUNC_CODE_INST_CMP2 = 28, + FUNC_CODE_INST_VSELECT = 29, + FUNC_CODE_INST_INBOUNDS_GEP_OLD = 30, + FUNC_CODE_INST_INDIRECTBR = 31, + /* 32: unused */ + FUNC_CODE_DEBUG_LOC_AGAIN = 33, + FUNC_CODE_INST_CALL = 34, + FUNC_CODE_DEBUG_LOC = 35, + FUNC_CODE_INST_FENCE = 36, + FUNC_CODE_INST_CMPXCHG_OLD = 37, + FUNC_CODE_INST_ATOMICRMW = 38, + FUNC_CODE_INST_RESUME = 39, + FUNC_CODE_INST_LANDINGPAD_OLD = 40, + FUNC_CODE_INST_LOADATOMIC = 41, + FUNC_CODE_INST_STOREATOMIC_OLD = 42, + FUNC_CODE_INST_GEP = 43, + FUNC_CODE_INST_STORE = 44, + FUNC_CODE_INST_STOREATOMIC = 45, + FUNC_CODE_INST_CMPXCHG = 46, + FUNC_CODE_INST_LANDINGPAD = 47, +}; + +enum func_abbrev_id { + FUNC_ABBREV_LOAD, + FUNC_ABBREV_BINOP, + FUNC_ABBREV_BINOP_FLAGS, + FUNC_ABBREV_CAST, + FUNC_ABBREV_RET_VOID, + FUNC_ABBREV_RET_VAL, + FUNC_ABBREV_UNREACHABLE, + FUNC_ABBREV_GEP, +}; + +static const struct dxil_abbrev +func_abbrevs[] = { + [FUNC_ABBREV_LOAD] = { + { LITERAL(FUNC_CODE_INST_LOAD), VBR(6), TYPE_INDEX, VBR(4), + FIXED(1) }, 5 + }, + [FUNC_ABBREV_BINOP] = { + { LITERAL(FUNC_CODE_INST_BINOP), VBR(6), VBR(6), FIXED(4) }, 4 + }, + [FUNC_ABBREV_BINOP_FLAGS] = { + { LITERAL(FUNC_CODE_INST_BINOP), VBR(6), VBR(6), FIXED(4), + FIXED(7) }, 5 + }, + [FUNC_ABBREV_CAST] = { + { LITERAL(FUNC_CODE_INST_CAST), VBR(6), TYPE_INDEX, FIXED(4) }, 4 + }, + [FUNC_ABBREV_RET_VOID] = { { LITERAL(FUNC_CODE_INST_RET) }, 1 }, + [FUNC_ABBREV_RET_VAL] = { { LITERAL(FUNC_CODE_INST_RET), VBR(6) }, 2 }, + [FUNC_ABBREV_UNREACHABLE] = { + { LITERAL(FUNC_CODE_INST_UNREACHABLE) }, 1 + }, + [FUNC_ABBREV_GEP] = { + { LITERAL(FUNC_CODE_INST_GEP), FIXED(1), TYPE_INDEX, ARRAY, + VBR(6) }, 5 + }, +}; + +static bool +emit_func_abbrev_record(struct dxil_module *m, enum func_abbrev_id abbrev, + const uint64_t *data, size_t size) +{ + assert(abbrev < ARRAY_SIZE(func_abbrevs)); + return emit_record_abbrev(&m->buf, abbrev + DXIL_FIRST_APPLICATION_ABBREV, + func_abbrevs + abbrev, data, size); +} + +static bool +define_abbrev(struct dxil_module *m, const struct dxil_abbrev *a) +{ + if (!dxil_buffer_emit_abbrev_id(&m->buf, DXIL_DEFINE_ABBREV) || + !dxil_buffer_emit_vbr_bits(&m->buf, a->num_operands, 5)) + return false; + + for (int i = 0; i < a->num_operands; ++i) { + unsigned is_literal = a->operands[i].type == DXIL_OP_LITERAL; + if (!dxil_buffer_emit_bits(&m->buf, is_literal, 1)) + return false; + if (a->operands[i].type == DXIL_OP_LITERAL) { + if (!dxil_buffer_emit_vbr_bits(&m->buf, a->operands[i].value, 8)) + return false; + } else { + if (!dxil_buffer_emit_bits(&m->buf, a->operands[i].type, 3)) + return false; + if (a->operands[i].type == DXIL_OP_FIXED) { + if (!dxil_buffer_emit_vbr_bits(&m->buf, + a->operands[i].encoding_data, 5)) + return false; + } else if (a->operands[i].type == DXIL_OP_VBR) { + if (!dxil_buffer_emit_vbr_bits(&m->buf, + a->operands[i].encoding_data, 5)) + return false; + } + } + } + + return true; +} + +enum dxil_blockinfo_code { + DXIL_BLOCKINFO_CODE_SETBID = 1, + DXIL_BLOCKINFO_CODE_BLOCKNAME = 2, + DXIL_BLOCKINFO_CODE_SETRECORDNAME = 3 +}; + +static bool +switch_to_block(struct dxil_module *m, uint32_t block) +{ + return emit_record_int(m, DXIL_BLOCKINFO_CODE_SETBID, block); +} + +enum dxil_standard_block { + DXIL_BLOCKINFO = 0, + DXIL_FIRST_APPLICATION_BLOCK = 8 +}; + +enum dxil_llvm_block { + DXIL_MODULE = DXIL_FIRST_APPLICATION_BLOCK, + DXIL_PARAMATTR = DXIL_FIRST_APPLICATION_BLOCK + 1, + DXIL_PARAMATTR_GROUP = DXIL_FIRST_APPLICATION_BLOCK + 2, + DXIL_CONST_BLOCK = DXIL_FIRST_APPLICATION_BLOCK + 3, + DXIL_FUNCTION_BLOCK = DXIL_FIRST_APPLICATION_BLOCK + 4, + DXIL_VALUE_SYMTAB_BLOCK = DXIL_FIRST_APPLICATION_BLOCK + 6, + DXIL_METADATA_BLOCK = DXIL_FIRST_APPLICATION_BLOCK + 7, + DXIL_TYPE_BLOCK = DXIL_FIRST_APPLICATION_BLOCK + 9, +}; + +enum value_symtab_code { + VST_CODE_ENTRY = 1, + VST_CODE_BBENTRY = 2 +}; + +enum value_symtab_abbrev_id { + VST_ABBREV_ENTRY_8, + VST_ABBREV_ENTRY_7, + VST_ABBREV_ENTRY_6, + VST_ABBREV_BBENTRY_6, +}; + +static struct dxil_abbrev value_symtab_abbrevs[] = { + [VST_ABBREV_ENTRY_8] = { { FIXED(3), VBR(8), ARRAY, FIXED(8) }, 4 }, + [VST_ABBREV_ENTRY_7] = { + { LITERAL(VST_CODE_ENTRY), VBR(8), ARRAY, FIXED(7), }, 4 + }, + [VST_ABBREV_ENTRY_6] = { + { LITERAL(VST_CODE_ENTRY), VBR(8), ARRAY, CHAR6, }, 4 + }, + [VST_ABBREV_BBENTRY_6] = { + { LITERAL(VST_CODE_BBENTRY), VBR(8), ARRAY, CHAR6, }, 4 + }, +}; + +static bool +emit_value_symtab_abbrevs(struct dxil_module *m) +{ + if (!switch_to_block(m, DXIL_VALUE_SYMTAB_BLOCK)) + return false; + + for (int i = 0; i < ARRAY_SIZE(value_symtab_abbrevs); ++i) { + if (!define_abbrev(m, value_symtab_abbrevs + i)) + return false; + } + + return true; +} + +static bool +emit_const_abbrevs(struct dxil_module *m) +{ + if (!switch_to_block(m, DXIL_CONST_BLOCK)) + return false; + + for (int i = 0; i < ARRAY_SIZE(const_abbrevs); ++i) { + if (!define_abbrev(m, const_abbrevs + i)) + return false; + } + + return true; +} + +static bool +emit_function_abbrevs(struct dxil_module *m) +{ + if (!switch_to_block(m, DXIL_FUNCTION_BLOCK)) + return false; + + for (int i = 0; i < ARRAY_SIZE(func_abbrevs); ++i) { + if (!define_abbrev(m, func_abbrevs + i)) + return false; + } + + return true; +} + +static bool +emit_blockinfo(struct dxil_module *m) +{ + return enter_subblock(m, DXIL_BLOCKINFO, 2) && + emit_value_symtab_abbrevs(m) && + emit_const_abbrevs(m) && + emit_function_abbrevs(m) && + exit_block(m); +} + +enum attribute_codes { + PARAMATTR_GRP_CODE_ENTRY = 3, + PARAMATTR_CODE_ENTRY = 2 +}; + +static bool +emit_attrib_group(struct dxil_module *m, int id, uint32_t slot, + const struct dxil_attrib *attrs, size_t num_attrs) +{ + uint64_t record[64]; + record[0] = id; + record[1] = slot; + size_t size = 2; + + for (int i = 0; i < num_attrs; ++i) { + uint64_t kind; + switch (attrs[i].type) { + case DXIL_ATTR_ENUM: + assert(size < ARRAY_SIZE(record) - 2); + record[size++] = 0; + record[size++] = attrs[i].kind; + break; + + default: + unreachable("unsupported attrib type"); + } + } + + return emit_record(m, PARAMATTR_GRP_CODE_ENTRY, record, size); +} + +static bool +emit_attrib_group_table(struct dxil_module *m) +{ + if (!enter_subblock(m, DXIL_PARAMATTR_GROUP, 3)) + return false; + + struct attrib_set *as; + int id = 1; + LIST_FOR_EACH_ENTRY(as, &m->attr_set_list, head) { + if (!emit_attrib_group(m, id, UINT32_MAX, as->attrs, as->num_attrs)) + return false; + id++; + } + + return exit_block(m); +} + +static bool +emit_attribute_table(struct dxil_module *m) +{ + if (!enter_subblock(m, DXIL_PARAMATTR, 3)) + return false; + + struct attrib_set *as; + int id = 1; + LIST_FOR_EACH_ENTRY(as, &m->attr_set_list, head) { + if (!emit_record_int(m, PARAMATTR_CODE_ENTRY, id)) + return false; + id++; + } + + return exit_block(m); +} + +static bool +emit_type_table_abbrevs(struct dxil_module *m) +{ + for (int i = 0; i < ARRAY_SIZE(type_table_abbrevs); ++i) { + if (!define_abbrev(m, type_table_abbrevs + i)) + return false; + } + + return true; +} + +static bool +emit_float_type(struct dxil_module *m, unsigned bit_size) +{ + switch (bit_size) { + case 16: return emit_record(m, TYPE_CODE_HALF, NULL, 0); + case 32: return emit_record(m, TYPE_CODE_FLOAT, NULL, 0); + case 64: return emit_record(m, TYPE_CODE_DOUBLE, NULL, 0); + default: + unreachable("unexpected bit_size for float type"); + } +} + +static bool +emit_pointer_type(struct dxil_module *m, int type_index) +{ + uint64_t data[] = { TYPE_CODE_POINTER, type_index, 0 }; + return emit_type_table_abbrev_record(m, TYPE_TABLE_ABBREV_POINTER, + data, ARRAY_SIZE(data)); +} + +static bool +emit_struct_name(struct dxil_module *m, const char *name) +{ + uint64_t temp[256]; + assert(strlen(name) < ARRAY_SIZE(temp)); + + for (int i = 0; i < strlen(name); ++i) + temp[i] = name[i]; + + return emit_record(m, TYPE_CODE_STRUCT_NAME, temp, strlen(name)); +} + +static bool +emit_struct_name_char6(struct dxil_module *m, const char *name) +{ + uint64_t temp[256]; + assert(strlen(name) < ARRAY_SIZE(temp) - 1); + + temp[0] = TYPE_CODE_STRUCT_NAME; + for (int i = 0; i < strlen(name); ++i) + temp[i + 1] = name[i]; + + return emit_type_table_abbrev_record(m, TYPE_TABLE_ABBREV_STRUCT_NAME, + temp, 1 + strlen(name)); +} + +static bool +emit_struct_type(struct dxil_module *m, const struct dxil_type *type) +{ + enum type_table_abbrev_id abbrev = TYPE_TABLE_ABBREV_STRUCT_ANON; + enum type_codes type_code = TYPE_CODE_STRUCT_ANON; + if (type->struct_def.name) { + abbrev = TYPE_TABLE_ABBREV_STRUCT_NAMED; + type_code = TYPE_CODE_STRUCT_NAMED; + if (is_char6_string(type->struct_def.name)) { + if (!emit_struct_name_char6(m, type->struct_def.name)) + return false; + } else { + if (!emit_struct_name(m, type->struct_def.name)) + return false; + } + } + + uint64_t temp[256]; + assert(type->struct_def.elem.num_types < ARRAY_SIZE(temp) - 2); + temp[0] = type_code; + temp[1] = 0; /* packed */ + for (int i = 0; i < type->struct_def.elem.num_types; ++i) { + assert(type->struct_def.elem.types[i]->id >= 0); + temp[2 + i] = type->struct_def.elem.types[i]->id; + } + + return emit_type_table_abbrev_record(m, abbrev, temp, + 2 + type->struct_def.elem.num_types); +} + +static bool +emit_array_type(struct dxil_module *m, const struct dxil_type *type) +{ + assert(type->array_or_vector_def.elem_type->id >= 0); + uint64_t data[] = { + TYPE_CODE_ARRAY, + type->array_or_vector_def.num_elems, + type->array_or_vector_def.elem_type->id + }; + return emit_type_table_abbrev_record(m, TYPE_TABLE_ABBREV_ARRAY, data, + ARRAY_SIZE(data)); +} + +static bool +emit_function_type(struct dxil_module *m, const struct dxil_type *type) +{ + uint64_t temp[256]; + assert(type->function_def.args.num_types < ARRAY_SIZE(temp) - 3); + assert(type->function_def.ret_type->id >= 0); + + temp[0] = TYPE_CODE_FUNCTION; + temp[1] = 0; // vararg + temp[2] = type->function_def.ret_type->id; + for (int i = 0; i < type->function_def.args.num_types; ++i) { + assert(type->function_def.args.types[i]->id >= 0); + temp[3 + i] = type->function_def.args.types[i]->id; + } + + return emit_type_table_abbrev_record(m, TYPE_TABLE_ABBREV_FUNCTION, + temp, 3 + type->function_def.args.num_types); +} + +static bool +emit_vector_type(struct dxil_module *m, const struct dxil_type *type) +{ + uint64_t temp[3]; + temp[0] = TYPE_CODE_VECTOR; + temp[1] = type->array_or_vector_def.num_elems; + temp[2] = type->array_or_vector_def.elem_type->id; + + return emit_type_table_abbrev_record(m, TYPE_TABLE_ABBREV_VECTOR , temp, 3); +} + +static bool +emit_metadata_type(struct dxil_module *m) +{ + return emit_record(m, TYPE_CODE_METADATA, NULL, 0); +} + +static bool +emit_type(struct dxil_module *m, struct dxil_type *type) +{ + switch (type->type) { + case TYPE_VOID: + return emit_record(m, TYPE_CODE_VOID, NULL, 0); + + case TYPE_INTEGER: + return emit_record_int(m, TYPE_CODE_INTEGER, type->int_bits); + + case TYPE_FLOAT: + return emit_float_type(m, type->float_bits); + + case TYPE_POINTER: + return emit_pointer_type(m, type->ptr_target_type->id); + + case TYPE_STRUCT: + return emit_struct_type(m, type); + + case TYPE_ARRAY: + return emit_array_type(m, type); + + case TYPE_FUNCTION: + return emit_function_type(m, type); + + case TYPE_VECTOR: + return emit_vector_type(m, type); + + default: + unreachable("unexpected type->type"); + } +} + +static bool +emit_type_table(struct dxil_module *m) +{ + if (!enter_subblock(m, DXIL_TYPE_BLOCK, 4) || + !emit_type_table_abbrevs(m) || + !emit_record_int(m, 1, 1 + list_length(&m->type_list))) + return false; + + list_for_each_entry(struct dxil_type, type, &m->type_list, head) { + if (!emit_type(m, type)) + return false; + } + + return emit_metadata_type(m) && + exit_block(m); +} + +static struct dxil_const * +create_const(struct dxil_module *m, const struct dxil_type *type, bool undef) +{ + struct dxil_const *ret = ralloc_size(m->ralloc_ctx, + sizeof(struct dxil_const)); + if (ret) { + ret->value.id = -1; + ret->value.type = type; + ret->undef = undef; + list_addtail(&ret->head, &m->const_list); + } + return ret; +} + +static const struct dxil_value * +get_int_const(struct dxil_module *m, const struct dxil_type *type, + intmax_t value) +{ + assert(type && type->type == TYPE_INTEGER); + + struct dxil_const *c; + LIST_FOR_EACH_ENTRY(c, &m->const_list, head) { + if (c->value.type != type || c->undef) + continue; + + if (c->int_value == value) + return &c->value; + } + + c = create_const(m, type, false); + if (!c) + return NULL; + + c->int_value = value; + return &c->value; +} + +const struct dxil_value * +dxil_module_get_int1_const(struct dxil_module *m, bool value) +{ + const struct dxil_type *type = get_int1_type(m); + if (!type) + return NULL; + + return get_int_const(m, type, value); +} + +const struct dxil_value * +dxil_module_get_int8_const(struct dxil_module *m, int8_t value) +{ + const struct dxil_type *type = get_int8_type(m); + if (!type) + return NULL; + + return get_int_const(m, type, value); +} + +const struct dxil_value * +dxil_module_get_int16_const(struct dxil_module *m, int16_t value) +{ + const struct dxil_type *type = get_int16_type(m); + if (!type) + return NULL; + + return get_int_const(m, type, value); +} + +const struct dxil_value * +dxil_module_get_int32_const(struct dxil_module *m, int32_t value) +{ + const struct dxil_type *type = get_int32_type(m); + if (!type) + return NULL; + + return get_int_const(m, type, value); +} + +const struct dxil_value * +dxil_module_get_int64_const(struct dxil_module *m, int64_t value) +{ + const struct dxil_type *type = get_int64_type(m); + if (!type) + return NULL; + + return get_int_const(m, type, value); +} + +const struct dxil_value * +dxil_module_get_int_const(struct dxil_module *m, intmax_t value, + unsigned bit_size) +{ + switch (bit_size) { + case 1: + assert(value == 0 || value == 1); + return dxil_module_get_int1_const(m, value); + + case 8: + assert(INT8_MIN <= value && value <= INT8_MAX); + return dxil_module_get_int8_const(m, value); + + case 16: + assert(INT16_MIN <= value && value <= INT16_MAX); + return dxil_module_get_int16_const(m, value); + + case 32: + assert(INT32_MIN <= value && value <= INT32_MAX); + return dxil_module_get_int32_const(m, value); + + case 64: + assert(INT64_MIN <= value && value <= INT64_MAX); + return dxil_module_get_int64_const(m, value); + + default: + unreachable("unsupported bit-width"); + } +} + +const struct dxil_value * +dxil_module_get_float_const(struct dxil_module *m, float value) +{ + const struct dxil_type *type = get_float32_type(m); + if (!type) + return NULL; + + struct dxil_const *c; + LIST_FOR_EACH_ENTRY(c, &m->const_list, head) { + if (c->value.type != type || c->undef) + continue; + + if (c->float_value == value) + return &c->value; + } + + c = create_const(m, type, false); + if (!c) + return NULL; + + c->float_value = value; + return &c->value; +} + +const struct dxil_value * +dxil_module_get_double_const(struct dxil_module *m, double value) +{ + const struct dxil_type *type = get_float64_type(m); + if (!type) + return NULL; + + struct dxil_const *c; + LIST_FOR_EACH_ENTRY(c, &m->const_list, head) { + if (c->value.type != type || c->undef) + continue; + + if (c->float_value == value) + return &c->value; + } + + c = create_const(m, type, false); + if (!c) + return NULL; + + c->float_value = value; + return &c->value; +} + +const struct dxil_value * +dxil_module_get_array_const(struct dxil_module *m, const struct dxil_type *type, + const struct dxil_value **values) +{ + assert(type->type == TYPE_ARRAY); + unsigned int num_values = type->array_or_vector_def.num_elems; + + struct dxil_const *c; + LIST_FOR_EACH_ENTRY(c, &m->const_list, head) { + if (c->value.type != type || c->undef) + continue; + + if (!memcmp(c->array_values, values, sizeof(*values) * num_values)) + return &c->value; + } + + c = create_const(m, type, false); + if (!c) + return NULL; + void *tmp = + ralloc_array(m->ralloc_ctx, struct dxil_value *, num_values); + memcpy(tmp, values, sizeof(*values) * num_values); + c->array_values = tmp; + + return &c->value; +} + +const struct dxil_value * +dxil_module_get_undef(struct dxil_module *m, const struct dxil_type *type) +{ + assert(type != NULL); + + struct dxil_const *c; + LIST_FOR_EACH_ENTRY(c, &m->const_list, head) { + if (c->value.type != type) + continue; + + if (c->undef) + return &c->value; + } + + c = create_const(m, type, true); + return c ? &c->value : NULL; +} + +enum dxil_module_code { + DXIL_MODULE_CODE_VERSION = 1, + DXIL_MODULE_CODE_TRIPLE = 2, + DXIL_MODULE_CODE_DATALAYOUT = 3, + DXIL_MODULE_CODE_ASM = 4, + DXIL_MODULE_CODE_SECTIONNAME = 5, + DXIL_MODULE_CODE_DEPLIB = 6, + DXIL_MODULE_CODE_GLOBALVAR = 7, + DXIL_MODULE_CODE_FUNCTION = 8, + DXIL_MODULE_CODE_ALIAS = 9, + DXIL_MODULE_CODE_PURGEVALS = 10, + DXIL_MODULE_CODE_GCNAME = 11, + DXIL_MODULE_CODE_COMDAT = 12, +}; + +static bool +emit_target_triple(struct dxil_module *m, const char *triple) +{ + uint64_t temp[256]; + assert(strlen(triple) < ARRAY_SIZE(temp)); + + for (int i = 0; i < strlen(triple); ++i) + temp[i] = triple[i]; + + return emit_record(m, DXIL_MODULE_CODE_TRIPLE, temp, strlen(triple)); +} + +static bool +emit_datalayout(struct dxil_module *m, const char *datalayout) +{ + uint64_t temp[256]; + assert(strlen(datalayout) < ARRAY_SIZE(temp)); + + for (int i = 0; i < strlen(datalayout); ++i) + temp[i] = datalayout[i]; + + return emit_record(m, DXIL_MODULE_CODE_DATALAYOUT, + temp, strlen(datalayout)); +} + +static const struct dxil_value * +add_gvar(struct dxil_module *m, const char *name, + const struct dxil_type *type, const struct dxil_type *value_type, + enum dxil_address_space as, int align, const struct dxil_value *value) +{ + struct dxil_gvar *gvar = ralloc_size(m->ralloc_ctx, + sizeof(struct dxil_gvar)); + if (!gvar) + return NULL; + + gvar->type = type; + gvar->name = ralloc_strdup(m->ralloc_ctx, name); + gvar->as = as; + gvar->align = align; + gvar->constant = !!value; + gvar->initializer = value; + + gvar->value.id = -1; + gvar->value.type = value_type; + + list_addtail(&gvar->head, &m->gvar_list); + return &gvar->value; +} + +const struct dxil_value * +dxil_add_global_var(struct dxil_module *m, const char *name, + const struct dxil_type *type, + enum dxil_address_space as, int align, + const struct dxil_value *value) +{ + return add_gvar(m, name, type, type, as, align, value); +} + +const struct dxil_value * +dxil_add_global_ptr_var(struct dxil_module *m, const char *name, + const struct dxil_type *type, + enum dxil_address_space as, int align, + const struct dxil_value *value) +{ + return add_gvar(m, name, type, dxil_module_get_pointer_type(m, type), + as, align, value); +} + +static struct dxil_func * +add_function(struct dxil_module *m, const char *name, + const struct dxil_type *type, + bool decl, unsigned attr_set) +{ + assert(type->type == TYPE_FUNCTION); + + struct dxil_func *func = ralloc_size(m->ralloc_ctx, + sizeof(struct dxil_func)); + if (!func) + return NULL; + + func->name = ralloc_strdup(func, name); + if (!func->name) { + return NULL; + } + + func->type = type; + func->decl = decl; + func->attr_set = attr_set; + + func->value.id = -1; + func->value.type = type->function_def.ret_type; + list_addtail(&func->head, &m->func_list); + return func; +} + +const struct dxil_func * +dxil_add_function_def(struct dxil_module *m, const char *name, + const struct dxil_type *type) +{ + return add_function(m, name, type, false, 0); +} + +static unsigned +get_attr_set(struct dxil_module *m, enum dxil_attr_kind attr) +{ + struct dxil_attrib attrs[2] = { + { DXIL_ATTR_ENUM, DXIL_ATTR_KIND_NO_UNWIND }, + { DXIL_ATTR_ENUM, attr } + }; + + int index = 1; + struct attrib_set *as; + LIST_FOR_EACH_ENTRY(as, &m->attr_set_list, head) { + if (!memcmp(as->attrs, attrs, sizeof(attrs))) + return index; + index++; + } + + as = ralloc_size(m->ralloc_ctx, sizeof(struct attrib_set)); + if (!as) + return 0; + + memcpy(as->attrs, attrs, sizeof(attrs)); + as->num_attrs = 1; + if (attr != DXIL_ATTR_KIND_NONE) + as->num_attrs++; + + list_addtail(&as->head, &m->attr_set_list); + assert(list_length(&m->attr_set_list) == index); + return index; +} + +const struct dxil_func * +dxil_add_function_decl(struct dxil_module *m, const char *name, + const struct dxil_type *type, + enum dxil_attr_kind attr) +{ + unsigned attr_set = get_attr_set(m, attr); + if (!attr_set) + return NULL; + + return add_function(m, name, type, true, attr_set); +} + +static bool +emit_module_info_function(struct dxil_module *m, int type, bool declaration, + int attr_set_index) +{ + uint64_t data[] = { + type, 0/* address space */, declaration, 0/* linkage */, + attr_set_index, 0/* alignment */, 0 /* section */, 0 /* visibility */, + 0 /* GC */, 0 /* unnamed addr */, 0 /* prologue data */, + 0 /* storage class */, 0 /* comdat */, 0 /* prefix-data */, + 0 /* personality */ + }; + return emit_record(m, DXIL_MODULE_CODE_FUNCTION, data, ARRAY_SIZE(data)); +} + +enum gvar_var_flags { + GVAR_FLAG_CONSTANT = (1 << 0), + GVAR_FLAG_EXPLICIT_TYPE = (1 << 1), +}; + +enum gvar_var_linkage { + GVAR_LINKAGE_EXTERNAL = 0, + GVAR_LINKAGE_APPENDING = 2, + GVAR_LINKAGE_INTERNAL = 3, + GVAR_LINKAGE_EXTERNAL_WEAK = 7, + GVAR_LINKAGE_COMMON = 8, + GVAR_LINKAGE_PRIVATE = 9, + GVAR_LINKAGE_AVAILABLE_EXTERNALLY = 12, + GVAR_LINKAGE_WEAK_ANY = 16, + GVAR_LINKAGE_WEAK_ODR = 17, + GVAR_LINKAGE_LINK_ONCE_ODR = 19, +}; + +static bool +emit_module_info_global(struct dxil_module *m, const struct dxil_gvar *gvar, + const struct dxil_abbrev *simple_gvar_abbr) +{ + uint64_t data[] = { + DXIL_MODULE_CODE_GLOBALVAR, + gvar->type->id, + (gvar->as << 2) | GVAR_FLAG_EXPLICIT_TYPE | + (gvar->constant ? GVAR_FLAG_CONSTANT : 0), + gvar->initializer ? gvar->initializer->id + 1 : 0, + (gvar->initializer ? GVAR_LINKAGE_INTERNAL : GVAR_LINKAGE_EXTERNAL), + util_logbase2(gvar->align) + 1, + 0 + }; + return emit_record_abbrev(&m->buf, 4, simple_gvar_abbr, + data, ARRAY_SIZE(data)); +} + +static bool +emit_module_info(struct dxil_module *m) +{ + struct dxil_gvar *gvar; + int max_global_type = 0; + int max_alignment = 0; + LIST_FOR_EACH_ENTRY(gvar, &m->gvar_list, head) { + assert(gvar->type->id >= 0); + max_global_type = MAX2(max_global_type, gvar->type->id); + max_alignment = MAX2(max_alignment, gvar->align); + } + + struct dxil_abbrev simple_gvar_abbr = { + { LITERAL(DXIL_MODULE_CODE_GLOBALVAR), + FIXED(util_logbase2(max_global_type) + 1), + VBR(6), VBR(6), FIXED(5), + FIXED(util_logbase2(max_alignment) + 1), + LITERAL(0) }, 7 + }; + + if (!emit_target_triple(m, "dxil-ms-dx") || + !emit_datalayout(m, "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64") || + !define_abbrev(m, &simple_gvar_abbr)) + return false; + + LIST_FOR_EACH_ENTRY(gvar, &m->gvar_list, head) { + assert(gvar->type->id >= 0); + if (!emit_module_info_global(m, gvar, &simple_gvar_abbr)) + return false; + } + + struct dxil_func *func; + LIST_FOR_EACH_ENTRY(func, &m->func_list, head) { + assert(func->type->id >= 0); + if (!emit_module_info_function(m, func->type->id, func->decl, + func->attr_set)) + return false; + } + + return true; +} + +static bool +emit_module_const_abbrevs(struct dxil_module *m) +{ + /* these are unused for now, so let's not even record them */ + struct dxil_abbrev abbrevs[] = { + { { LITERAL(CST_CODE_AGGREGATE), ARRAY, FIXED(5) }, 3 }, + { { LITERAL(CST_CODE_STRING), ARRAY, FIXED(8) }, 3 }, + { { LITERAL(CST_CODE_CSTRING), ARRAY, FIXED(7) }, 3 }, + { { LITERAL(CST_CODE_CSTRING), ARRAY, CHAR6 }, 3 }, + }; + + for (int i = 0; i < ARRAY_SIZE(abbrevs); ++i) { + if (!define_abbrev(m, abbrevs + i)) + return false; + } + + return true; +} + +static bool +emit_set_type(struct dxil_module *m, unsigned type_index) +{ + uint64_t data[] = { CST_CODE_SETTYPE, type_index }; + return emit_const_abbrev_record(m, CONST_ABBREV_SETTYPE, + data, ARRAY_SIZE(data)); +} + +static bool +emit_null_value(struct dxil_module *m) +{ + return emit_record_no_abbrev(&m->buf, CST_CODE_NULL, NULL, 0); +} + +static bool +emit_undef_value(struct dxil_module *m) +{ + return emit_record_no_abbrev(&m->buf, CST_CODE_UNDEF, NULL, 0); +} + +uint64_t +encode_signed(int64_t value) +{ + return value >= 0 ? + (value << 1) : + ((-value << 1) | 1); +} + +static bool +emit_int_value(struct dxil_module *m, int64_t value) +{ + if (!value) + return emit_null_value(m); + + uint64_t data[] = { CST_CODE_INTEGER, encode_signed(value) }; + return emit_const_abbrev_record(m, CONST_ABBREV_INTEGER, + data, ARRAY_SIZE(data)); +} + +static bool +emit_float_value(struct dxil_module *m, float value) +{ + uint64_t data = fui(value); + if (data == UINT32_C(0)) + return emit_null_value(m); + return emit_record_no_abbrev(&m->buf, CST_CODE_FLOAT, &data, 1); +} + +static bool +emit_double_value(struct dxil_module *m, double value) +{ + union di u; + u.d = value; + if (u.ui == UINT64_C(0)) + return emit_null_value(m); + return emit_record_no_abbrev(&m->buf, CST_CODE_FLOAT, &u.ui, 1); +} + +static bool +emit_aggregate_values(struct dxil_module *m, const struct dxil_value **values, + int num_values) +{ + uint64_t *value_ids = ralloc_array(m->ralloc_ctx, uint64_t, num_values); + int i; + + for (i = 0; i < num_values; i++) + value_ids[i] = values[i]->id; + + return emit_record_no_abbrev(&m->buf, CST_CODE_AGGREGATE, value_ids, + num_values); +} + +static bool +emit_consts(struct dxil_module *m) +{ + const struct dxil_type *curr_type = NULL; + struct dxil_const *c; + LIST_FOR_EACH_ENTRY(c, &m->const_list, head) { + assert(c->value.id >= 0); + assert(c->value.type != NULL); + if (curr_type != c->value.type) { + assert(c->value.type->id >= 0); + if (!emit_set_type(m, c->value.type->id)) + return false; + curr_type = c->value.type; + } + + if (c->undef) { + if (!emit_undef_value(m)) + return false; + continue; + } + + switch (curr_type->type) { + case TYPE_INTEGER: + if (!emit_int_value(m, c->int_value)) + return false; + break; + + case TYPE_FLOAT: + switch (curr_type->float_bits) { + case 32: + if (!emit_float_value(m, c->float_value)) + return false; + break; + case 64: + if (!emit_double_value(m, c->float_value)) + return false; + break; + default: + unreachable("unexpected float_bits"); + } + break; + + case TYPE_ARRAY: + if (!emit_aggregate_values(m, c->array_values, + c->value.type->array_or_vector_def.num_elems)) + return false; + break; + + default: + unreachable("unsupported constant type"); + } + } + + return true; +} + +bool +emit_module_consts(struct dxil_module *m) +{ + return enter_subblock(m, DXIL_CONST_BLOCK, 4) && + emit_module_const_abbrevs(m) && + emit_consts(m) && + exit_block(m); +} + +static bool +emit_value_symtab_abbrev_record(struct dxil_module *m, + enum const_abbrev_id abbrev, + const uint64_t *data, size_t size) +{ + assert(abbrev < ARRAY_SIZE(value_symtab_abbrevs)); + return emit_record_abbrev(&m->buf, abbrev + DXIL_FIRST_APPLICATION_ABBREV, + value_symtab_abbrevs + abbrev, data, size); +} + +static bool +emit_symtab_entry(struct dxil_module *m, unsigned value, const char *name) +{ + uint64_t temp[256]; + assert(strlen(name) < ARRAY_SIZE(temp) - 2); + + temp[0] = VST_CODE_ENTRY; + temp[1] = value; + for (int i = 0; i < strlen(name); ++i) + temp[i + 2] = name[i]; + + enum value_symtab_abbrev_id abbrev = VST_ABBREV_ENTRY_8; + if (is_char6_string(name)) + abbrev = VST_ABBREV_ENTRY_6; + else if (is_char7_string(name)) + abbrev = VST_ABBREV_ENTRY_7; + + return emit_value_symtab_abbrev_record(m, abbrev, temp, 2 + strlen(name)); +} + +static bool +emit_value_symbol_table(struct dxil_module *m) +{ + if (!enter_subblock(m, DXIL_VALUE_SYMTAB_BLOCK, 4)) + return false; + + struct dxil_func *func; + LIST_FOR_EACH_ENTRY(func, &m->func_list, head) { + if (!emit_symtab_entry(m, func->value.id, func->name)) + return false; + } + struct dxil_gvar *gvar; + LIST_FOR_EACH_ENTRY(gvar, &m->gvar_list, head) { + if (!emit_symtab_entry(m, gvar->value.id, gvar->name)) + return false; + } + return exit_block(m); +} + +enum metadata_codes { + METADATA_STRING = 1, + METADATA_VALUE = 2, + METADATA_NODE = 3, + METADATA_NAME = 4, + METADATA_KIND = 6, + METADATA_NAMED_NODE = 10 +}; + +enum metadata_abbrev_id { + METADATA_ABBREV_STRING, + METADATA_ABBREV_NAME +}; + +static const struct dxil_abbrev metadata_abbrevs[] = { + [METADATA_ABBREV_STRING] = { + { LITERAL(METADATA_STRING), ARRAY, FIXED(8) }, 3 + }, + [METADATA_ABBREV_NAME] = { + { LITERAL(METADATA_NAME), ARRAY, FIXED(8) }, 3 + }, +}; + +static bool +emit_metadata_abbrevs(struct dxil_module *m) +{ + for (int i = 0; i < ARRAY_SIZE(metadata_abbrevs); ++i) { + if (!define_abbrev(m, metadata_abbrevs + i)) + return false; + } + return true; +} + +static struct dxil_mdnode * +create_mdnode(struct dxil_module *m, enum mdnode_type type) +{ + struct dxil_mdnode *ret = rzalloc_size(m->ralloc_ctx, + sizeof(struct dxil_mdnode)); + if (ret) { + ret->type = type; + ret->id = list_length(&m->mdnode_list) + 1; /* zero is reserved for NULL nodes */ + list_addtail(&ret->head, &m->mdnode_list); + } + return ret; +} + +const struct dxil_mdnode * +dxil_get_metadata_string(struct dxil_module *m, const char *str) +{ + assert(str); + + struct dxil_mdnode *n; + LIST_FOR_EACH_ENTRY(n, &m->mdnode_list, head) { + if (n->type == MD_STRING && + !strcmp(n->string, str)) + return n; + } + + n = create_mdnode(m, MD_STRING); + if (n) { + n->string = ralloc_strdup(n, str); + if (!n->string) + return NULL; + } + return n; +} + +const struct dxil_mdnode * +dxil_get_metadata_value(struct dxil_module *m, const struct dxil_type *type, + const struct dxil_value *value) +{ + struct dxil_mdnode *n; + LIST_FOR_EACH_ENTRY(n, &m->mdnode_list, head) { + if (n->type == MD_VALUE && + n->value.type == type && + n->value.value == value) + return n; + } + + n = create_mdnode(m, MD_VALUE); + if (n) { + n->value.type = type; + n->value.value = value; + } + return n; +} + +const struct dxil_mdnode * +dxil_get_metadata_func(struct dxil_module *m, const struct dxil_func *func) +{ + const struct dxil_type *ptr_type = + dxil_module_get_pointer_type(m, func->type); + return dxil_get_metadata_value(m, ptr_type, &func->value); +} + +const struct dxil_mdnode * +dxil_get_metadata_node(struct dxil_module *m, + const struct dxil_mdnode *subnodes[], + size_t num_subnodes) +{ + struct dxil_mdnode *n; + LIST_FOR_EACH_ENTRY(n, &m->mdnode_list, head) { + if (n->type == MD_NODE && + n->node.num_subnodes == num_subnodes && + !memcmp(n->node.subnodes, subnodes, sizeof(struct dxil_mdnode *) * + num_subnodes)) + return n; + } + + n = create_mdnode(m, MD_NODE); + if (n) { + n->node.subnodes = ralloc_array(n, struct dxil_mdnode *, num_subnodes); + if (!n->node.subnodes) + return NULL; + + memcpy(n->node.subnodes, subnodes, sizeof(struct dxil_mdnode *) * + num_subnodes); + n->node.num_subnodes = num_subnodes; + } + return n; +} + +const struct dxil_mdnode * +dxil_get_metadata_int1(struct dxil_module *m, bool value) +{ + const struct dxil_type *type = get_int1_type(m); + if (!type) + return NULL; + + const struct dxil_value *const_value = get_int_const(m, type, value); + if (!const_value) + return NULL; + + return dxil_get_metadata_value(m, type, const_value); +} + +const struct dxil_mdnode * +dxil_get_metadata_int8(struct dxil_module *m, int8_t value) +{ + const struct dxil_type *type = get_int8_type(m); + if (!type) + return NULL; + + const struct dxil_value *const_value = get_int_const(m, type, value); + if (!const_value) + return NULL; + + return dxil_get_metadata_value(m, type, const_value); +} + +const struct dxil_mdnode * +dxil_get_metadata_int32(struct dxil_module *m, int32_t value) +{ + const struct dxil_type *type = get_int32_type(m); + if (!type) + return NULL; + + const struct dxil_value *const_value = get_int_const(m, type, value); + if (!const_value) + return NULL; + + return dxil_get_metadata_value(m, type, const_value); +} + +const struct dxil_mdnode * +dxil_get_metadata_int64(struct dxil_module *m, int64_t value) +{ + const struct dxil_type *type = get_int64_type(m); + if (!type) + return NULL; + + const struct dxil_value *const_value = get_int_const(m, type, value); + if (!const_value) + return NULL; + + return dxil_get_metadata_value(m, type, const_value); +} + +bool +dxil_add_metadata_named_node(struct dxil_module *m, const char *name, + const struct dxil_mdnode *subnodes[], + size_t num_subnodes) +{ + struct dxil_named_node *n = ralloc_size(m->ralloc_ctx, + sizeof(struct dxil_named_node)); + if (!n) + return false; + + n->name = ralloc_strdup(n, name); + if (!n->name) + return false; + + n->subnodes = ralloc_array(n, struct dxil_mdnode *, num_subnodes); + if (!n->subnodes) + return false; + + memcpy(n->subnodes, subnodes, sizeof(struct dxil_mdnode *) * + num_subnodes); + n->num_subnodes = num_subnodes; + + list_addtail(&n->head, &m->md_named_node_list); + return true; +} + +static bool +emit_metadata_value(struct dxil_module *m, const struct dxil_type *type, + const struct dxil_value *value) +{ + assert(type->id >= 0 && value->id >= 0); + uint64_t data[2] = { type->id, value->id }; + return emit_record(m, METADATA_VALUE, data, ARRAY_SIZE(data)); +} + +static bool +emit_metadata_abbrev_record(struct dxil_module *m, + enum metadata_abbrev_id abbrev, + const uint64_t *data, size_t size) +{ + assert(abbrev < ARRAY_SIZE(metadata_abbrevs)); + return emit_record_abbrev(&m->buf, abbrev + DXIL_FIRST_APPLICATION_ABBREV, + metadata_abbrevs + abbrev, data, size); +} + +static bool +emit_metadata_string(struct dxil_module *m, const char *str) +{ + uint64_t data[256]; + assert(strlen(str) < ARRAY_SIZE(data) - 1); + data[0] = METADATA_STRING; + for (size_t i = 0; i < strlen(str); ++i) + data[i + 1] = str[i]; + + return emit_metadata_abbrev_record(m, METADATA_ABBREV_STRING, + data, strlen(str) + 1); +} + +static bool +emit_metadata_node(struct dxil_module *m, + const struct dxil_mdnode *subnodes[], + size_t num_subnodes) +{ + uint64_t data[256]; + assert(num_subnodes < ARRAY_SIZE(data)); + for (size_t i = 0; i < num_subnodes; ++i) + data[i] = subnodes[i] ? subnodes[i]->id : 0; + + return emit_record(m, METADATA_NODE, data, num_subnodes); +} + +static bool +emit_mdnode(struct dxil_module *m, struct dxil_mdnode *n) +{ + switch (n->type) { + case MD_STRING: + return emit_metadata_string(m, n->string); + + case MD_VALUE: + return emit_metadata_value(m, n->value.type, n->value.value); + + case MD_NODE: + return emit_metadata_node(m, n->node.subnodes, n->node.num_subnodes); + + default: + unreachable("unexpected n->type"); + } +} + +static bool +emit_metadata_nodes(struct dxil_module *m) +{ + list_for_each_entry(struct dxil_mdnode, n, &m->mdnode_list, head) { + if (!emit_mdnode(m, n)) + return false; + } + return true; +} + +static bool +emit_metadata_name(struct dxil_module *m, const char *name) +{ + uint64_t data[256]; + assert(strlen(name) < ARRAY_SIZE(data) - 1); + data[0] = METADATA_NAME; + for (size_t i = 0; i < strlen(name); ++i) + data[i + 1] = name[i]; + + return emit_metadata_abbrev_record(m, METADATA_ABBREV_NAME, + data, strlen(name) + 1); +} + +static bool +emit_metadata_named_node(struct dxil_module *m, const char *name, + const struct dxil_mdnode *subnodes[], + size_t num_subnodes) +{ + uint64_t data[256]; + assert(num_subnodes < ARRAY_SIZE(data)); + for (size_t i = 0; i < num_subnodes; ++i) { + assert(subnodes[i]->id > 0); /* NULL nodes not allowed */ + data[i] = subnodes[i]->id - 1; + } + + return emit_metadata_name(m, name) && + emit_record(m, METADATA_NAMED_NODE, data, num_subnodes); +} + +static bool +emit_metadata_named_nodes(struct dxil_module *m) +{ + struct dxil_named_node *n; + LIST_FOR_EACH_ENTRY(n, &m->md_named_node_list, head) { + if (!emit_metadata_named_node(m, n->name, n->subnodes, + n->num_subnodes)) + return false; + } + return true; +} + +static bool +emit_metadata(struct dxil_module *m) +{ + return enter_subblock(m, DXIL_METADATA_BLOCK, 3) && + emit_metadata_abbrevs(m) && + emit_metadata_nodes(m) && + emit_metadata_named_nodes(m) && + exit_block(m); +} + +static struct dxil_instr * +create_instr(struct dxil_module *m, enum instr_type type, + const struct dxil_type *ret_type) +{ + struct dxil_instr *ret = ralloc_size(m->ralloc_ctx, + sizeof(struct dxil_instr)); + if (ret) { + ret->type = type; + ret->value.id = -1; + ret->value.type = ret_type; + ret->has_value = false; + list_addtail(&ret->head, &m->instr_list); + } + return ret; +} + +static bool +legal_arith_type(const struct dxil_type *type) +{ + switch (type->type) { + case TYPE_INTEGER: + return type->int_bits == 1 || + type->int_bits == 16 || + type->int_bits == 32 || + type->int_bits == 64; + + case TYPE_FLOAT: + return type->float_bits == 16 || + type->float_bits == 32 || + type->float_bits == 64; + + default: + return false; + } +} + +const struct dxil_value * +dxil_emit_binop(struct dxil_module *m, enum dxil_bin_opcode opcode, + const struct dxil_value *op0, const struct dxil_value *op1, + enum dxil_opt_flags flags) +{ + assert(types_equal(op0->type, op1->type)); + assert(legal_arith_type(op0->type)); + struct dxil_instr *instr = create_instr(m, INSTR_BINOP, op0->type); + if (!instr) + return NULL; + + instr->binop.opcode = opcode; + instr->binop.operands[0] = op0; + instr->binop.operands[1] = op1; + instr->binop.flags = flags; + instr->has_value = true; + return &instr->value; +} + +const struct dxil_value * +dxil_emit_cmp(struct dxil_module *m, enum dxil_cmp_pred pred, + const struct dxil_value *op0, const struct dxil_value *op1) +{ + assert(types_equal(op0->type, op1->type)); + assert(legal_arith_type(op0->type)); + struct dxil_instr *instr = create_instr(m, INSTR_CMP, get_int1_type(m)); + if (!instr) + return NULL; + + instr->cmp.pred = pred; + instr->cmp.operands[0] = op0; + instr->cmp.operands[1] = op1; + instr->has_value = true; + return &instr->value; +} + +const struct dxil_value * +dxil_emit_select(struct dxil_module *m, + const struct dxil_value *op0, + const struct dxil_value *op1, + const struct dxil_value *op2) +{ + assert(types_equal(op0->type, get_int1_type(m))); + assert(types_equal(op1->type, op2->type)); + assert(legal_arith_type(op1->type)); + + struct dxil_instr *instr = create_instr(m, INSTR_SELECT, op1->type); + if (!instr) + return NULL; + + instr->select.operands[0] = op0; + instr->select.operands[1] = op1; + instr->select.operands[2] = op2; + instr->has_value = true; + return &instr->value; +} + +const struct dxil_value * +dxil_emit_cast(struct dxil_module *m, enum dxil_cast_opcode opcode, + const struct dxil_type *type, + const struct dxil_value *value) +{ + assert(legal_arith_type(value->type)); + assert(legal_arith_type(type)); + + struct dxil_instr *instr = create_instr(m, INSTR_CAST, type); + if (!instr) + return NULL; + + instr->cast.opcode = opcode; + instr->cast.type = type; + instr->cast.value = value; + instr->has_value = true; + return &instr->value; +} + +bool +dxil_emit_branch(struct dxil_module *m, const struct dxil_value *cond, + unsigned true_block, unsigned false_block) +{ + assert(!cond || types_equal(cond->type, get_int1_type(m))); + + struct dxil_instr *instr = create_instr(m, INSTR_BR, + dxil_module_get_void_type(m)); + if (!instr) + return false; + + instr->br.cond = cond; + instr->br.succ[0] = true_block; + instr->br.succ[1] = false_block; + m->curr_block++; + return true; +} + +const struct dxil_value * +dxil_instr_get_return_value(struct dxil_instr *instr) +{ + return instr->has_value ? &instr->value : NULL; +} + +struct dxil_instr * +dxil_emit_phi(struct dxil_module *m, const struct dxil_type *type) +{ + assert(legal_arith_type(type)); + + struct dxil_instr *instr = create_instr(m, INSTR_PHI, type); + if (!instr) + return NULL; + + instr->phi.type = type; + instr->phi.num_incoming = 0; + instr->has_value = true; + + return instr; +} + +void +dxil_phi_set_incoming(struct dxil_instr *instr, + const struct dxil_value *incoming_values[], + const unsigned incoming_blocks[], + size_t num_incoming) +{ + assert(instr->type == INSTR_PHI); + assert(num_incoming > 0); + assert(num_incoming < ARRAY_SIZE(instr->phi.incoming)); + for (int i = 0; i < num_incoming; ++i) { + assert(incoming_values[i]); + assert(types_equal(incoming_values[i]->type, instr->phi.type)); + + instr->phi.incoming[i].value = incoming_values[i]; + instr->phi.incoming[i].block = incoming_blocks[i]; + } + instr->phi.num_incoming = num_incoming; +} + +static struct dxil_instr * +create_call_instr(struct dxil_module *m, + const struct dxil_func *func, + const struct dxil_value **args, size_t num_args) +{ + assert(num_args == func->type->function_def.args.num_types); + for (size_t i = 0; i < num_args; ++ i) + assert(types_equal(func->type->function_def.args.types[i], args[i]->type)); + + struct dxil_instr *instr = create_instr(m, INSTR_CALL, + func->type->function_def.ret_type); + if (instr) { + instr->call.func = func; + instr->call.args = ralloc_array(instr, struct dxil_value *, num_args); + if (!args) + return false; + memcpy(instr->call.args, args, sizeof(struct dxil_value *) * num_args); + instr->call.num_args = num_args; + } + return instr; +} + +const struct dxil_value * +dxil_emit_call(struct dxil_module *m, + const struct dxil_func *func, + const struct dxil_value **args, size_t num_args) +{ + assert(func->type->function_def.ret_type->type != TYPE_VOID); + + struct dxil_instr *instr = create_call_instr(m, func, args, num_args); + if (!instr) + return NULL; + + instr->has_value = true; + return &instr->value; +} + +bool +dxil_emit_call_void(struct dxil_module *m, + const struct dxil_func *func, + const struct dxil_value **args, size_t num_args) +{ + assert(func->type->function_def.ret_type->type == TYPE_VOID); + + struct dxil_instr *instr = create_call_instr(m, func, args, num_args); + if (!instr) + return false; + + return true; +} + +bool +dxil_emit_ret_void(struct dxil_module *m) +{ + struct dxil_instr *instr = create_instr(m, INSTR_RET, + dxil_module_get_void_type(m)); + if (!instr) + return false; + + instr->ret.value = NULL; + m->curr_block++; + return true; +} + +const struct dxil_value * +dxil_emit_extractval(struct dxil_module *m, const struct dxil_value *src, + const unsigned int index) +{ + assert(src->type->type == TYPE_STRUCT); + assert(index < src->type->struct_def.elem.num_types); + + struct dxil_instr *instr = + create_instr(m, INSTR_EXTRACTVAL, + src->type->struct_def.elem.types[index]); + if (!instr) + return NULL; + + instr->extractval.src = src; + instr->extractval.type = src->type; + instr->extractval.idx = index; + instr->has_value = true; + + return &instr->value; +} + +const struct dxil_value * +dxil_emit_alloca(struct dxil_module *m, const struct dxil_type *alloc_type, + const struct dxil_type *size_type, + const struct dxil_value *size, + unsigned int align) +{ + assert(size_type && size_type->type == TYPE_INTEGER); + + const struct dxil_type *return_type = + dxil_module_get_pointer_type(m, alloc_type); + if (!return_type) + return NULL; + + struct dxil_instr *instr = create_instr(m, INSTR_ALLOCA, return_type); + if (!instr) + return NULL; + + instr->alloca.alloc_type = alloc_type; + instr->alloca.size_type = size_type; + instr->alloca.size = size; + instr->alloca.align = util_logbase2(align) + 1; + assert(instr->alloca.align < (1 << 5)); + instr->alloca.align |= 1 << 6; + + instr->has_value = true; + return &instr->value; +} + +static const struct dxil_type * +get_deref_type(const struct dxil_type *type) +{ + switch (type->type) { + case TYPE_POINTER: return type->ptr_target_type; + case TYPE_ARRAY: return type->array_or_vector_def.elem_type; + default: unreachable("unexpected type"); + } +} + +const struct dxil_value * +dxil_emit_gep_inbounds(struct dxil_module *m, + const struct dxil_value **operands, + size_t num_operands) +{ + assert(num_operands > 0); + const struct dxil_type *source_elem_type = + get_deref_type(operands[0]->type); + + const struct dxil_type *type = operands[0]->type; + for (int i = 1; i < num_operands; ++i) { + assert(operands[i]->type == get_int32_type(m)); + type = get_deref_type(type); + } + + type = dxil_module_get_pointer_type(m, type); + if (!type) + return NULL; + + struct dxil_instr *instr = create_instr(m, INSTR_GEP, type); + if (!instr) + return NULL; + + instr->gep.operands = ralloc_array(instr, struct dxil_value *, + num_operands); + if (!instr->gep.operands) + return NULL; + + instr->gep.source_elem_type = source_elem_type; + memcpy(instr->gep.operands, operands, + sizeof(struct dxil_value *) * num_operands); + instr->gep.num_operands = num_operands; + instr->gep.inbounds = true; + + instr->has_value = true; + return &instr->value; +} + +const struct dxil_value * +dxil_emit_load(struct dxil_module *m, const struct dxil_value *ptr, + unsigned align, + bool is_volatile) +{ + assert(ptr->type->type == TYPE_POINTER || + ptr->type->type == TYPE_ARRAY); + const struct dxil_type *type = ptr->type->type == TYPE_POINTER ? + ptr->type->ptr_target_type : + ptr->type->array_or_vector_def.elem_type; + + struct dxil_instr *instr = create_instr(m, INSTR_LOAD, type); + if (!instr) + return false; + + instr->load.ptr = ptr; + instr->load.type = type; + instr->load.align = util_logbase2(align) + 1; + instr->load.is_volatile = is_volatile; + + instr->has_value = true; + return &instr->value; +} + +bool +dxil_emit_store(struct dxil_module *m, const struct dxil_value *value, + const struct dxil_value *ptr, unsigned align, + bool is_volatile) +{ + assert(legal_arith_type(value->type)); + + struct dxil_instr *instr = create_instr(m, INSTR_STORE, + dxil_module_get_void_type(m)); + if (!instr) + return false; + + instr->store.value = value; + instr->store.ptr = ptr; + instr->store.align = util_logbase2(align) + 1; + instr->store.is_volatile = is_volatile; + return true; +} + +const struct dxil_value * +dxil_emit_cmpxchg(struct dxil_module *m, const struct dxil_value *cmpval, + const struct dxil_value *newval, + const struct dxil_value *ptr, bool is_volatile, + enum dxil_atomic_ordering ordering, + enum dxil_sync_scope syncscope) +{ + assert(ptr->type->type == TYPE_POINTER); + + struct dxil_instr *instr = create_instr(m, INSTR_CMPXCHG, + ptr->type->ptr_target_type); + if (!instr) + return false; + + instr->cmpxchg.cmpval = cmpval; + instr->cmpxchg.newval = newval; + instr->cmpxchg.ptr = ptr; + instr->cmpxchg.is_volatile = is_volatile; + instr->cmpxchg.ordering = ordering; + instr->cmpxchg.syncscope = syncscope; + + instr->has_value = true; + return &instr->value; +} + +const struct dxil_value * +dxil_emit_atomicrmw(struct dxil_module *m, const struct dxil_value *value, + const struct dxil_value *ptr, enum dxil_rmw_op op, + bool is_volatile, enum dxil_atomic_ordering ordering, + enum dxil_sync_scope syncscope) +{ + assert(ptr->type->type == TYPE_POINTER); + + struct dxil_instr *instr = create_instr(m, INSTR_ATOMICRMW, + ptr->type->ptr_target_type); + if (!instr) + return false; + + instr->atomicrmw.value = value; + instr->atomicrmw.ptr = ptr; + instr->atomicrmw.op = op; + instr->atomicrmw.is_volatile = is_volatile; + instr->atomicrmw.ordering = ordering; + instr->atomicrmw.syncscope = syncscope; + + instr->has_value = true; + return &instr->value; +} + +static bool +emit_binop(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_BINOP); + assert(instr->value.id > instr->binop.operands[0]->id); + assert(instr->value.id > instr->binop.operands[1]->id); + + if (instr->binop.flags) { + uint64_t data[] = { + FUNC_CODE_INST_BINOP, + instr->value.id - instr->binop.operands[0]->id, + instr->value.id - instr->binop.operands[1]->id, + instr->binop.opcode, + instr->binop.flags + }; + return emit_func_abbrev_record(m, FUNC_ABBREV_BINOP_FLAGS, + data, ARRAY_SIZE(data)); + } + uint64_t data[] = { + FUNC_CODE_INST_BINOP, + instr->value.id - instr->binop.operands[0]->id, + instr->value.id - instr->binop.operands[1]->id, + instr->binop.opcode + }; + return emit_func_abbrev_record(m, FUNC_ABBREV_BINOP, + data, ARRAY_SIZE(data)); +} + +static bool +emit_cmp(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_CMP); + assert(instr->value.id > instr->cmp.operands[0]->id); + assert(instr->value.id > instr->cmp.operands[1]->id); + uint64_t data[] = { + instr->value.id - instr->cmp.operands[0]->id, + instr->value.id - instr->cmp.operands[1]->id, + instr->cmp.pred + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_CMP2, + data, ARRAY_SIZE(data)); +} + +static bool +emit_select(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_SELECT); + assert(instr->value.id > instr->select.operands[0]->id); + assert(instr->value.id > instr->select.operands[1]->id); + assert(instr->value.id > instr->select.operands[2]->id); + uint64_t data[] = { + instr->value.id - instr->select.operands[1]->id, + instr->value.id - instr->select.operands[2]->id, + instr->value.id - instr->select.operands[0]->id + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_VSELECT, + data, ARRAY_SIZE(data)); +} + +static bool +emit_cast(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_CAST); + assert(instr->value.id > instr->cast.value->id); + uint64_t data[] = { + FUNC_CODE_INST_CAST, + instr->value.id - instr->cast.value->id, + instr->cast.type->id, + instr->cast.opcode + }; + return emit_func_abbrev_record(m, FUNC_ABBREV_CAST, + data, ARRAY_SIZE(data)); +} + +bool +emit_branch(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_BR); + assert(instr->br.succ[0] < m->num_basic_block_ids); + assert(m->basic_block_ids[instr->br.succ[0]] >= 0); + + if (!instr->br.cond) { + /* unconditional branch */ + uint64_t succ = m->basic_block_ids[instr->br.succ[0]]; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_BR, &succ, 1); + } + /* conditional branch */ + assert(instr->value.id > instr->br.cond->id); + assert(instr->br.succ[1] < m->num_basic_block_ids); + assert(m->basic_block_ids[instr->br.succ[1]] >= 0); + + uint64_t data[] = { + m->basic_block_ids[instr->br.succ[0]], + m->basic_block_ids[instr->br.succ[1]], + instr->value.id - instr->br.cond->id + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_BR, + data, ARRAY_SIZE(data)); +} + +bool +emit_phi(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_PHI); + uint64_t data[128]; + data[0] = instr->phi.type->id; + assert(instr->phi.num_incoming > 0); + for (int i = 0; i < instr->phi.num_incoming; ++i) { + int64_t value_delta = instr->value.id - instr->phi.incoming[i].value->id; + data[1 + i * 2] = encode_signed(value_delta); + assert(instr->phi.incoming[i].block < m->num_basic_block_ids); + assert(m->basic_block_ids[instr->phi.incoming[i].block] >= 0); + data[1 + i * 2 + 1] = m->basic_block_ids[instr->phi.incoming[i].block]; + } + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_PHI, + data, 1 + 2 * instr->phi.num_incoming); +} + +static bool +emit_extractval(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_EXTRACTVAL); + assert(instr->value.id > instr->extractval.src->id); + assert(instr->value.id > instr->extractval.type->id); + + /* relative value ID, followed by absolute type ID (only if + * forward-declared), followed by n indices */ + uint64_t data[] = { + instr->value.id - instr->extractval.src->id, + instr->extractval.idx + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_EXTRACTVAL, + data, ARRAY_SIZE(data)); +} + +static bool +emit_call(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_CALL); + assert(instr->call.func->value.id >= 0 && instr->value.id >= 0); + assert(instr->call.func->type->id >= 0); + assert(instr->call.func->value.id <= instr->value.id); + int value_id_delta = instr->value.id - instr->call.func->value.id; + + uint64_t data[256]; + data[0] = 0; // attribute id + data[1] = 1 << 15; // calling convention etc + data[2] = instr->call.func->type->id; + data[3] = value_id_delta; + + assert(instr->call.num_args < ARRAY_SIZE(data) - 4); + for (size_t i = 0; i < instr->call.num_args; ++i) { + assert(instr->call.args[i]->id >= 0); + data[4 + i] = instr->value.id - instr->call.args[i]->id; + } + + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_CALL, + data, 4 + instr->call.num_args); +} + +static bool +emit_ret(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_RET); + + if (instr->ret.value) { + assert(instr->ret.value->id >= 0); + uint64_t data[] = { FUNC_CODE_INST_RET, instr->ret.value->id }; + return emit_func_abbrev_record(m, FUNC_ABBREV_RET_VAL, + data, ARRAY_SIZE(data)); + } + + uint64_t data[] = { FUNC_CODE_INST_RET }; + return emit_func_abbrev_record(m, FUNC_ABBREV_RET_VOID, + data, ARRAY_SIZE(data)); +} + +static bool +emit_alloca(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_ALLOCA); + assert(instr->alloca.alloc_type->id >= 0); + assert(instr->alloca.size_type->id >= 0); + assert(instr->alloca.size->id >= 0); + + uint64_t data[] = { + instr->alloca.alloc_type->id, + instr->alloca.size_type->id, + instr->alloca.size->id, + instr->alloca.align, + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_ALLOCA, + data, ARRAY_SIZE(data)); +} + +static bool +emit_gep(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_GEP); + assert(instr->gep.source_elem_type->id >= 0); + + uint64_t data[256]; + data[0] = FUNC_CODE_INST_GEP; + data[1] = instr->gep.inbounds; + data[2] = instr->gep.source_elem_type->id; + + assert(instr->gep.num_operands < ARRAY_SIZE(data) - 3); + for (int i = 0; i < instr->gep.num_operands; ++i) { + assert(instr->value.id > instr->gep.operands[i]->id); + data[3 + i] = instr->value.id - instr->gep.operands[i]->id; + } + return emit_func_abbrev_record(m, FUNC_ABBREV_GEP, + data, 3 + instr->gep.num_operands); +} + +static bool +emit_load(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_LOAD); + assert(instr->value.id > instr->load.ptr->id); + assert(instr->load.type->id >= 0); + + uint64_t data[] = { + instr->value.id - instr->load.ptr->id, + instr->load.type->id, + instr->load.align, + instr->load.is_volatile + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_LOAD, + data, ARRAY_SIZE(data)); +} +static bool +emit_store(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_STORE); + assert(instr->value.id > instr->store.value->id); + assert(instr->value.id > instr->store.ptr->id); + + uint64_t data[] = { + instr->value.id - instr->store.ptr->id, + instr->value.id - instr->store.value->id, + instr->store.align, + instr->store.is_volatile + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_STORE, + data, ARRAY_SIZE(data)); +} + +static bool +emit_cmpxchg(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_CMPXCHG); + assert(instr->value.id > instr->cmpxchg.cmpval->id); + assert(instr->value.id > instr->cmpxchg.newval->id); + assert(instr->value.id > instr->cmpxchg.ptr->id); + uint64_t data[] = { + instr->value.id - instr->cmpxchg.ptr->id, + instr->value.id - instr->cmpxchg.cmpval->id, + instr->value.id - instr->cmpxchg.newval->id, + instr->cmpxchg.is_volatile, + instr->cmpxchg.ordering, + instr->cmpxchg.syncscope, + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_CMPXCHG_OLD, + data, ARRAY_SIZE(data)); +} + +static bool +emit_atomicrmw(struct dxil_module *m, struct dxil_instr *instr) +{ + assert(instr->type == INSTR_ATOMICRMW); + assert(instr->value.id > instr->atomicrmw.value->id); + assert(instr->value.id > instr->atomicrmw.ptr->id); + uint64_t data[] = { + instr->value.id - instr->atomicrmw.ptr->id, + instr->value.id - instr->atomicrmw.value->id, + instr->atomicrmw.op, + instr->atomicrmw.is_volatile, + instr->atomicrmw.ordering, + instr->atomicrmw.syncscope, + }; + return emit_record_no_abbrev(&m->buf, FUNC_CODE_INST_ATOMICRMW, + data, ARRAY_SIZE(data)); +} + +static bool +emit_instr(struct dxil_module *m, struct dxil_instr *instr) +{ + switch (instr->type) { + case INSTR_BINOP: + return emit_binop(m, instr); + + case INSTR_CMP: + return emit_cmp(m, instr); + + case INSTR_SELECT: + return emit_select(m, instr); + + case INSTR_CAST: + return emit_cast(m, instr); + + case INSTR_BR: + return emit_branch(m, instr); + + case INSTR_PHI: + return emit_phi(m, instr); + + case INSTR_CALL: + return emit_call(m, instr); + + case INSTR_RET: + return emit_ret(m, instr); + + case INSTR_EXTRACTVAL: + return emit_extractval(m, instr); + + case INSTR_ALLOCA: + return emit_alloca(m, instr); + + case INSTR_GEP: + return emit_gep(m, instr); + + case INSTR_LOAD: + return emit_load(m, instr); + + case INSTR_STORE: + return emit_store(m, instr); + + case INSTR_ATOMICRMW: + return emit_atomicrmw(m, instr); + + case INSTR_CMPXCHG: + return emit_cmpxchg(m, instr); + + default: + unreachable("unexpected instruction type"); + } +} + +static bool +emit_function(struct dxil_module *m) +{ + if (!enter_subblock(m, DXIL_FUNCTION_BLOCK, 4) || + !emit_record_int(m, FUNC_CODE_DECLAREBLOCKS, m->curr_block)) + return false; + + list_for_each_entry(struct dxil_instr, instr, &m->instr_list, head) { + if (!emit_instr(m, instr)) + return false; + } + + return exit_block(m); +} + +static void +assign_values(struct dxil_module *m) +{ + int next_value_id = 0; + + struct dxil_gvar *gvar; + LIST_FOR_EACH_ENTRY(gvar, &m->gvar_list, head) { + gvar->value.id = next_value_id++; + } + + struct dxil_func *func; + LIST_FOR_EACH_ENTRY(func, &m->func_list, head) { + func->value.id = next_value_id++; + } + + struct dxil_const *c; + LIST_FOR_EACH_ENTRY(c, &m->const_list, head) { + c->value.id = next_value_id++; + } + + struct dxil_instr *instr; + LIST_FOR_EACH_ENTRY(instr, &m->instr_list, head) { + instr->value.id = next_value_id; + if (instr->has_value) + next_value_id++; + } +} + +bool +dxil_emit_module(struct dxil_module *m) +{ + assign_values(m); + return dxil_buffer_emit_bits(&m->buf, 'B', 8) && + dxil_buffer_emit_bits(&m->buf, 'C', 8) && + dxil_buffer_emit_bits(&m->buf, 0xC0, 8) && + dxil_buffer_emit_bits(&m->buf, 0xDE, 8) && + enter_subblock(m, DXIL_MODULE, 3) && + emit_record_int(m, DXIL_MODULE_CODE_VERSION, 1) && + emit_blockinfo(m) && + emit_attrib_group_table(m) && + emit_attribute_table(m) && + emit_type_table(m) && + emit_module_info(m) && + emit_module_consts(m) && + emit_metadata(m) && + emit_value_symbol_table(m) && + emit_function(m) && + exit_block(m); +} diff --git a/src/microsoft/compiler/dxil_module.h b/src/microsoft/compiler/dxil_module.h new file mode 100644 index 00000000000..353492e4418 --- /dev/null +++ b/src/microsoft/compiler/dxil_module.h @@ -0,0 +1,469 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + + /* + * See the DirectX Shader Compiler for documentation for DXIL details: + * https://github.com/Microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst + */ + +#ifndef DXIL_MODULE_H +#define DXIL_MODULE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dxil_buffer.h" +#include "dxil_signature.h" + +#include "util/list.h" + + +#define DXIL_SHADER_MAX_IO_ROWS 80 + +enum dxil_shader_kind { + DXIL_PIXEL_SHADER = 0, + DXIL_VERTEX_SHADER = 1, + DXIL_GEOMETRY_SHADER = 2, + DXIL_HULL_SHADER = 3, + DXIL_DOMAIN_SHADER = 4, + DXIL_COMPUTE_SHADER = 5, +}; + +extern int debug_dxil; + +enum dxil_debug_flags { + DXIL_DEBUG_VERBOSE = 1 << 0, + DXIL_DEBUG_DUMP_BLOB = 1 << 1, + DXIL_DEBUG_TRACE = 1 << 2, + DXIL_DEBUG_DUMP_MODULE = 1 << 3, +}; + +enum dxil_bin_opcode { + DXIL_BINOP_ADD = 0, + DXIL_BINOP_SUB = 1, + DXIL_BINOP_MUL = 2, + DXIL_BINOP_UDIV = 3, + DXIL_BINOP_SDIV = 4, + DXIL_BINOP_UREM = 5, + DXIL_BINOP_SREM = 6, + DXIL_BINOP_SHL = 7, + DXIL_BINOP_LSHR = 8, + DXIL_BINOP_ASHR = 9, + DXIL_BINOP_AND = 10, + DXIL_BINOP_OR = 11, + DXIL_BINOP_XOR = 12, + DXIL_BINOP_INSTR_COUNT +}; + +enum dxil_cast_opcode { + DXIL_CAST_TRUNC = 0, + DXIL_CAST_ZEXT = 1, + DXIL_CAST_SEXT = 2, + DXIL_CAST_FPTOUI = 3, + DXIL_CAST_FPTOSI = 4, + DXIL_CAST_UITOFP = 5, + DXIL_CAST_SITOFP = 6, + DXIL_CAST_FPTRUNC = 7, + DXIL_CAST_FPEXT = 8, + DXIL_CAST_PTRTOINT = 9, + DXIL_CAST_INTTOPTR = 10, + DXIL_CAST_BITCAST = 11, + DXIL_CAST_ADDRSPACECAST = 12, + DXIL_CAST_INSTR_COUNT +}; + +enum dxil_cmp_pred { + DXIL_FCMP_FALSE = 0, + DXIL_FCMP_OEQ = 1, + DXIL_FCMP_OGT = 2, + DXIL_FCMP_OGE = 3, + DXIL_FCMP_OLT = 4, + DXIL_FCMP_OLE = 5, + DXIL_FCMP_ONE = 6, + DXIL_FCMP_ORD = 7, + DXIL_FCMP_UNO = 8, + DXIL_FCMP_UEQ = 9, + DXIL_FCMP_UGT = 10, + DXIL_FCMP_UGE = 11, + DXIL_FCMP_ULT = 12, + DXIL_FCMP_ULE = 13, + DXIL_FCMP_UNE = 14, + DXIL_FCMP_TRUE = 15, + DXIL_ICMP_EQ = 32, + DXIL_ICMP_NE = 33, + DXIL_ICMP_UGT = 34, + DXIL_ICMP_UGE = 35, + DXIL_ICMP_ULT = 36, + DXIL_ICMP_ULE = 37, + DXIL_ICMP_SGT = 38, + DXIL_ICMP_SGE = 39, + DXIL_ICMP_SLT = 40, + DXIL_ICMP_SLE = 41, + DXIL_CMP_INSTR_COUNT +}; + +enum dxil_opt_flags { + DXIL_UNSAFE_ALGEBRA = (1 << 0), + DXIL_NO_NANS = (1 << 1), + DXIL_NO_INFS = (1 << 2), + DXIL_NO_SIGNED_ZEROS = (1 << 3), + DXIL_ALLOW_RECIPROCAL = (1 << 4) +}; + +struct dxil_features { + unsigned doubles : 1, + cs_4x_raw_sb : 1, + uavs_at_every_stage : 1, + use_64uavs : 1, + min_precision : 1, + dx11_1_double_extensions : 1, + dx11_1_shader_extensions : 1, + dx9_comparison_filtering : 1, + tiled_resources : 1, + stencil_ref : 1, + inner_coverage : 1, + typed_uav_load_additional_formats : 1, + rovs : 1, + array_layer_from_vs_or_ds : 1, + wave_ops : 1, + int64_ops : 1, + view_id : 1, + barycentrics : 1, + native_low_precision : 1, + shading_rate : 1, + raytracing_tier_1_1 : 1, + sampler_feedback : 1; +}; + +struct dxil_shader_info { + unsigned has_out_position:1; + unsigned has_out_depth:1; +}; + +struct dxil_module { + void *ralloc_ctx; + enum dxil_shader_kind shader_kind; + unsigned major_version, minor_version; + struct dxil_features feats; + unsigned raw_and_structured_buffers : 1; + struct dxil_shader_info info; + + struct dxil_buffer buf; + + unsigned num_sig_inputs; + unsigned num_sig_outputs; + unsigned num_psv_inputs; + unsigned num_psv_outputs; + + struct dxil_signature_record inputs[DXIL_SHADER_MAX_IO_ROWS]; + struct dxil_signature_record outputs[DXIL_SHADER_MAX_IO_ROWS]; + + struct dxil_psv_signature_element psv_inputs[DXIL_SHADER_MAX_IO_ROWS]; + struct dxil_psv_signature_element psv_outputs[DXIL_SHADER_MAX_IO_ROWS]; + + struct _mesa_string_buffer *sem_string_table; + struct dxil_psv_sem_index_table sem_index_table; + + struct { + unsigned abbrev_width; + intptr_t offset; + } blocks[16]; + size_t num_blocks; + + struct list_head type_list; + struct list_head gvar_list; + struct list_head func_list; + struct list_head attr_set_list; + struct list_head instr_list; + struct list_head const_list; + struct list_head mdnode_list; + struct list_head md_named_node_list; + const struct dxil_type *void_type; + const struct dxil_type *int1_type, *int8_type, *int16_type, + *int32_type, *int64_type; + const struct dxil_type *float16_type, *float32_type, *float64_type; + + struct rb_tree *functions; + + int *basic_block_ids; /* maps from "user" ids to LLVM ids */ + size_t num_basic_block_ids; + unsigned curr_block; +}; + +struct dxil_instr; +struct dxil_value; + +void +dxil_module_init(struct dxil_module *m, void *ralloc_ctx); + +void +dxil_module_release(struct dxil_module *m); + +const struct dxil_value * +dxil_add_global_var(struct dxil_module *m, const char *name, + const struct dxil_type *type, + enum dxil_address_space as, int align, + const struct dxil_value *value); + +const struct dxil_value * +dxil_add_global_ptr_var(struct dxil_module *m, const char *name, + const struct dxil_type *type, + enum dxil_address_space as, int align, + const struct dxil_value *value); + +const struct dxil_func * +dxil_add_function_def(struct dxil_module *m, const char *name, + const struct dxil_type *type); + +const struct dxil_func * +dxil_add_function_decl(struct dxil_module *m, const char *name, + const struct dxil_type *type, + enum dxil_attr_kind attr); + +const struct dxil_type * +dxil_module_get_void_type(struct dxil_module *m); + +const struct dxil_type * +dxil_module_get_int_type(struct dxil_module *m, unsigned bit_size); + +const struct dxil_type * +dxil_module_get_float_type(struct dxil_module *m, unsigned bit_size); + +const struct dxil_type * +dxil_module_get_pointer_type(struct dxil_module *m, + const struct dxil_type *target); + +const struct dxil_type * +dxil_get_overload_type(struct dxil_module *mod, enum overload_type overload); + +const struct dxil_type * +dxil_module_get_handle_type(struct dxil_module *m); + +const struct dxil_type * +dxil_module_get_cbuf_ret_type(struct dxil_module *mod, enum overload_type overload); + +const struct dxil_type * +dxil_module_get_res_type(struct dxil_module *m, enum dxil_resource_kind kind, + enum dxil_component_type comp_type, bool readwrite); + +const struct dxil_type * +dxil_module_get_resret_type(struct dxil_module *m, enum overload_type overload); + +const struct dxil_type * +dxil_module_get_dimret_type(struct dxil_module *m); + +const struct dxil_type * +dxil_module_get_struct_type(struct dxil_module *m, + const char *name, + const struct dxil_type **elem_types, + size_t num_elem_types); + +const struct dxil_type * +dxil_module_get_array_type(struct dxil_module *m, + const struct dxil_type *elem_type, + size_t num_elems); + +const struct dxil_type * +dxil_module_get_vector_type(struct dxil_module *m, + const struct dxil_type *elem_type, + size_t num_elems); + +const struct dxil_type * +dxil_module_add_function_type(struct dxil_module *m, + const struct dxil_type *ret_type, + const struct dxil_type **arg_types, + size_t num_arg_types); + +nir_alu_type +dxil_type_to_nir_type(const struct dxil_type *type); + +bool +dxil_value_type_equal_to(const struct dxil_value *value, + const struct dxil_type *lhs); + +bool +dxil_value_type_bitsize_equal_to(const struct dxil_value *value, unsigned bitsize); + +const struct dxil_type * +dxil_value_get_type(const struct dxil_value *value); + +const struct dxil_value * +dxil_module_get_int1_const(struct dxil_module *m, bool value); + +const struct dxil_value * +dxil_module_get_int8_const(struct dxil_module *m, int8_t value); + +const struct dxil_value * +dxil_module_get_int16_const(struct dxil_module *m, int16_t value); + +const struct dxil_value * +dxil_module_get_int32_const(struct dxil_module *m, int32_t value); + +const struct dxil_value * +dxil_module_get_int64_const(struct dxil_module *m, int64_t value); + +const struct dxil_value * +dxil_module_get_int_const(struct dxil_module *m, intmax_t value, + unsigned bit_size); + +const struct dxil_value * +dxil_module_get_float_const(struct dxil_module *m, float value); + +const struct dxil_value * +dxil_module_get_double_const(struct dxil_module *m, double value); + +const struct dxil_value * +dxil_module_get_array_const(struct dxil_module *m, const struct dxil_type *type, + const struct dxil_value **values); + +const struct dxil_value * +dxil_module_get_undef(struct dxil_module *m, const struct dxil_type *type); + +const struct dxil_mdnode * +dxil_get_metadata_string(struct dxil_module *m, const char *str); + +const struct dxil_mdnode * +dxil_get_metadata_value(struct dxil_module *m, const struct dxil_type *type, + const struct dxil_value *value); + +const struct dxil_mdnode * +dxil_get_metadata_func(struct dxil_module *m, const struct dxil_func *func); + +const struct dxil_mdnode * +dxil_get_metadata_int1(struct dxil_module *m, bool value); + +const struct dxil_mdnode * +dxil_get_metadata_int8(struct dxil_module *m, int8_t value); + +const struct dxil_mdnode * +dxil_get_metadata_int32(struct dxil_module *m, int32_t value); + +const struct dxil_mdnode * +dxil_get_metadata_int64(struct dxil_module *m, int64_t value); + +const struct dxil_mdnode * +dxil_get_metadata_node(struct dxil_module *m, + const struct dxil_mdnode *subnodes[], + size_t num_subnodes); + +bool +dxil_add_metadata_named_node(struct dxil_module *m, const char *name, + const struct dxil_mdnode *subnodes[], + size_t num_subnodes); + +const struct dxil_value * +dxil_emit_binop(struct dxil_module *m, enum dxil_bin_opcode opcode, + const struct dxil_value *op0, const struct dxil_value *op1, + enum dxil_opt_flags flags); + +const struct dxil_value * +dxil_emit_cmp(struct dxil_module *m, enum dxil_cmp_pred pred, + const struct dxil_value *op0, const struct dxil_value *op1); + +const struct dxil_value * +dxil_emit_select(struct dxil_module *m, + const struct dxil_value *op0, + const struct dxil_value *op1, + const struct dxil_value *op2); + +const struct dxil_value * +dxil_emit_extractval(struct dxil_module *m, const struct dxil_value *src, + const unsigned int index); + +const struct dxil_value * +dxil_emit_cast(struct dxil_module *m, enum dxil_cast_opcode opcode, + const struct dxil_type *type, + const struct dxil_value *value); + +bool +dxil_emit_branch(struct dxil_module *m, const struct dxil_value *cond, + unsigned true_block, unsigned false_block); + +const struct dxil_value * +dxil_instr_get_return_value(struct dxil_instr *instr); + +struct dxil_instr * +dxil_emit_phi(struct dxil_module *m, const struct dxil_type *type); + +void +dxil_phi_set_incoming(struct dxil_instr *instr, + const struct dxil_value *incoming_values[], + const unsigned incoming_blocks[], + size_t num_incoming); + +const struct dxil_value * +dxil_emit_call(struct dxil_module *m, + const struct dxil_func *func, + const struct dxil_value **args, size_t num_args); + +bool +dxil_emit_call_void(struct dxil_module *m, + const struct dxil_func *func, + const struct dxil_value **args, size_t num_args); + +bool +dxil_emit_ret_void(struct dxil_module *m); + +const struct dxil_value * +dxil_emit_alloca(struct dxil_module *m, const struct dxil_type *alloc_type, + const struct dxil_type *size_type, + const struct dxil_value *size, + unsigned int align); + +const struct dxil_value * +dxil_emit_gep_inbounds(struct dxil_module *m, + const struct dxil_value **operands, + size_t num_operands); + +const struct dxil_value * +dxil_emit_load(struct dxil_module *m, const struct dxil_value *ptr, + unsigned align, + bool is_volatile); + +bool +dxil_emit_store(struct dxil_module *m, const struct dxil_value *value, + const struct dxil_value *ptr, unsigned align, + bool is_volatile); + +const struct dxil_value * +dxil_emit_cmpxchg(struct dxil_module *m, const struct dxil_value *cmpval, + const struct dxil_value *newval, + const struct dxil_value *ptr, bool is_volatile, + enum dxil_atomic_ordering ordering, + enum dxil_sync_scope syncscope); + +const struct dxil_value * +dxil_emit_atomicrmw(struct dxil_module *m, const struct dxil_value *value, + const struct dxil_value *ptr, enum dxil_rmw_op op, + bool is_volatile, enum dxil_atomic_ordering ordering, + enum dxil_sync_scope syncscope); + +bool +dxil_emit_module(struct dxil_module *m); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/microsoft/compiler/dxil_signature.c b/src/microsoft/compiler/dxil_signature.c new file mode 100644 index 00000000000..9718a42ea5a --- /dev/null +++ b/src/microsoft/compiler/dxil_signature.c @@ -0,0 +1,589 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#include "dxil_enums.h" +#include "dxil_module.h" +#include "dxil_signature.h" + +#include "nir_to_dxil.h" +#include "glsl_types.h" +#include "util/u_debug.h" + +#include + + +struct semantic_info { + enum dxil_semantic_kind kind; + char name[64]; + int index; + enum dxil_prog_sig_comp_type comp_type; + uint8_t sig_comp_type; + int32_t start_row; + int32_t rows; + uint8_t start_col; + uint8_t cols; + uint8_t interpolation; + const char *sysvalue_name; +}; + + +static bool +is_depth_output(enum dxil_semantic_kind kind) +{ + return kind == DXIL_SEM_DEPTH || + kind == DXIL_SEM_STENCIL_REF; +} + +static uint8_t +get_interpolation(nir_variable *var) +{ + if (unlikely(var->data.centroid)) { + switch (var->data.interpolation) { + case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR_CENTROID; + case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT; + case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID; + case INTERP_MODE_SMOOTH: DXIL_INTERP_LINEAR_CENTROID; + + } + } else { + switch (var->data.interpolation) { + case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR; + case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT; + case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE; + case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR; + } + } + + return DXIL_INTERP_LINEAR; +} + +static const char * +in_sysvalue_name(nir_variable *var) +{ + switch (var->data.location) { + case VARYING_SLOT_POS: + return "POS"; + case VARYING_SLOT_FACE: + return "FACE"; + default: + return "NONE"; + } +} + +/* + * The signatures are written into the stream in two pieces: + * DxilProgramSignatureElement is a fixes size structure that gets dumped + * to the stream in order of the registers and each contains an offset + * to the semantic name string. Then these strings are dumped into the stream. + */ +static unsigned +get_additional_semantic_info(nir_variable *var, struct semantic_info *info, + unsigned next_row, bool is_gs_shader) +{ + const struct glsl_type *type = var->type; + + info->comp_type = + dxil_get_prog_sig_comp_type(var->type); + + bool is_depth = is_depth_output(info->kind); + info->sig_comp_type = dxil_get_comp_type(var->type); + + info->rows = 1; + if (info->kind == DXIL_SEM_TARGET) { + info->start_row = info->index; + } else if (is_depth || (info->kind == DXIL_SEM_PRIMITIVE_ID && is_gs_shader)) { + info->start_row = -1; + } else { + info->start_row = next_row; + if (glsl_type_is_array(type) && is_gs_shader) + type = glsl_without_array(type); + + if (glsl_type_is_array(type)) { + info->rows = glsl_get_aoa_size(type); + type = glsl_get_array_element(type); + assert(info->rows); + } + next_row += info->rows; + } + info->start_col = (uint8_t)var->data.location_frac; + if (glsl_type_is_array(type)) + type = glsl_get_array_element(type); + info->cols = (uint8_t)glsl_get_components(type); + + return next_row; +} + +typedef void (*semantic_info_proc)(nir_variable *var, struct semantic_info *info); + +static void +get_semantic_vs_in_name(nir_variable *var, struct semantic_info *info) +{ + const char *name = dxil_vs_attr_index_to_name(var->data.driver_location); + assert(strlen(name) < 63); + strcpy(info->name, name); + info->kind = DXIL_SEM_ARBITRARY; +} + +static void +get_semantic_sv_name(nir_variable *var, struct semantic_info *info) +{ + switch (var->data.location) { + case SYSTEM_VALUE_VERTEX_ID_ZERO_BASE: + info->kind = DXIL_SEM_VERTEX_ID; + break; + case SYSTEM_VALUE_FRONT_FACE: + info->kind = DXIL_SEM_IS_FRONT_FACE; + break; + case SYSTEM_VALUE_INSTANCE_ID: + info->kind = DXIL_SEM_INSTANCE_ID; + break; + case SYSTEM_VALUE_PRIMITIVE_ID: + info->kind = DXIL_SEM_PRIMITIVE_ID; + break; + default: + unreachable("unsupported system value"); + } + strncpy(info->name, var->name, 64); +} + +static void +get_semantic_ps_outname(nir_variable *var, struct semantic_info *info) +{ + info->kind = DXIL_SEM_INVALID; + switch (var->data.location) { + case FRAG_RESULT_COLOR: + snprintf(info->name, 64, "%s", "SV_Target"); + info->index = var->data.index; + info->kind = DXIL_SEM_TARGET; + break; + case FRAG_RESULT_DATA0: + case FRAG_RESULT_DATA1: + case FRAG_RESULT_DATA2: + case FRAG_RESULT_DATA3: + case FRAG_RESULT_DATA4: + case FRAG_RESULT_DATA5: + case FRAG_RESULT_DATA6: + case FRAG_RESULT_DATA7: + snprintf(info->name, 64, "%s", "SV_Target"); + info->index = var->data.location - FRAG_RESULT_DATA0; + if (var->data.location == FRAG_RESULT_DATA0 && + var->data.index > 0) + info->index = var->data.index; + info->kind = DXIL_SEM_TARGET; + break; + case FRAG_RESULT_DEPTH: + snprintf(info->name, 64, "%s", "SV_Depth"); + info->kind = DXIL_SEM_DEPTH; + break; + case FRAG_RESULT_STENCIL: + snprintf(info->name, 64, "%s", "SV_StencilRef"); + info->kind = DXIL_SEM_STENCIL_REF; //?? + break; + case FRAG_RESULT_SAMPLE_MASK: + snprintf(info->name, 64, "%s", "SV_Coverage"); + info->kind = DXIL_SEM_COVERAGE; //?? + break; + default: + snprintf(info->name, 64, "%s", "UNDEFINED"); + break; + } +} + +static void +get_semantic_name(nir_variable *var, struct semantic_info *info, + const struct glsl_type *type) +{ + info->kind = DXIL_SEM_INVALID; + info->interpolation = get_interpolation(var); + switch (var->data.location) { + + case VARYING_SLOT_POS: + assert(glsl_get_components(type) == 4); + snprintf(info->name, 64, "%s", "SV_Position"); + info->kind = DXIL_SEM_POSITION; + break; + + case VARYING_SLOT_FACE: + assert(glsl_get_components(var->type) == 1); + snprintf(info->name, 64, "%s", "SV_IsFrontFace"); + info->kind = DXIL_SEM_IS_FRONT_FACE; + break; + + case VARYING_SLOT_PRIMITIVE_ID: + assert(glsl_get_components(var->type) == 1); + snprintf(info->name, 64, "%s", "SV_PrimitiveID"); + info->kind = DXIL_SEM_PRIMITIVE_ID; + break; + + case VARYING_SLOT_CLIP_DIST1: + info->index = 1; + /* fallthrough */ + case VARYING_SLOT_CLIP_DIST0: + assert(var->data.location == VARYING_SLOT_CLIP_DIST1 || info->index == 0); + snprintf(info->name, 64, "%s", "SV_ClipDistance"); + info->kind = DXIL_SEM_CLIP_DISTANCE; + break; + + default: { + int index = var->data.location - VARYING_SLOT_POS; + const char idx1 = 'A' + (char)(index >> 4); + const char idx2 = 'A' + (char)(index & 0xf); + snprintf(info->name, 64, "VARYING%c%c", idx1, idx2); + info->kind = DXIL_SEM_ARBITRARY; + } + } +} + +static void +get_semantic_in_name(nir_variable *var, struct semantic_info *info) +{ + get_semantic_name(var, info, var->type); + info->sysvalue_name = in_sysvalue_name(var); +} + +static void +get_semantic_gs_in_name(nir_variable *var, struct semantic_info *info) +{ + /* geometry shader input varyings come as arrays, but we want to use + * the element type */ + const struct glsl_type *type = + glsl_type_is_array(var->type) ? glsl_without_array(var->type) : var->type; + + get_semantic_name(var, info, type); + info->sysvalue_name = in_sysvalue_name(var); +} + + +static enum dxil_prog_sig_semantic +prog_semantic_from_kind(enum dxil_semantic_kind kind) +{ + switch (kind) { + case DXIL_SEM_ARBITRARY: return DXIL_PROG_SEM_UNDEFINED; + case DXIL_SEM_VERTEX_ID: return DXIL_PROG_SEM_VERTEX_ID; + case DXIL_SEM_INSTANCE_ID: return DXIL_PROG_SEM_INSTANCE_ID; + case DXIL_SEM_POSITION: return DXIL_PROG_SEM_POSITION; + case DXIL_SEM_COVERAGE: return DXIL_PROG_SEM_COVERAGE; + case DXIL_SEM_INNER_COVERAGE: return DXIL_PROG_SEM_INNER_COVERAGE; + case DXIL_SEM_PRIMITIVE_ID: return DXIL_PROG_SEM_PRIMITIVE_ID; + case DXIL_SEM_SAMPLE_INDEX: return DXIL_PROG_SEM_SAMPLE_INDEX; + case DXIL_SEM_IS_FRONT_FACE: return DXIL_PROG_SEM_IS_FRONTFACE; + case DXIL_SEM_RENDERTARGET_ARRAY_INDEX: return DXIL_PROG_SEM_RENDERTARGET_ARRAY_INDEX; + case DXIL_SEM_VIEWPORT_ARRAY_INDEX: return DXIL_PROG_SEM_VIEWPORT_ARRAY_INDEX; + case DXIL_SEM_CLIP_DISTANCE: return DXIL_PROG_SEM_CLIP_DISTANCE; + case DXIL_SEM_CULL_DISTANCE: return DXIL_PROG_SEM_CULL_DISTANCE; + case DXIL_SEM_BARYCENTRICS: return DXIL_PROG_SEM_BARYCENTRICS; + case DXIL_SEM_SHADING_RATE: return DXIL_PROG_SEM_SHADING_RATE; + case DXIL_SEM_CULL_PRIMITIVE: return DXIL_PROG_SEM_CULL_PRIMITIVE; + case DXIL_SEM_TARGET: return DXIL_PROG_SEM_TARGET; + case DXIL_SEM_DEPTH: return DXIL_PROG_SEM_DEPTH; + case DXIL_SEM_DEPTH_LE: return DXIL_PROG_SEM_DEPTH_LE; + case DXIL_SEM_DEPTH_GE: return DXIL_PROG_SEM_DEPTH_GE; + case DXIL_SEM_STENCIL_REF: return DXIL_PROG_SEM_STENCIL_REF; + default: + return DXIL_PROG_SEM_UNDEFINED; + } +} + +static +uint32_t +copy_semantic_name_to_string(struct _mesa_string_buffer *string_out, const char *name) +{ + /* copy the semantic name */ + uint32_t retval = string_out->length; + size_t name_len = strlen(name) + 1; + _mesa_string_buffer_append_len(string_out, name, name_len); + return retval; +} + +static +uint32_t +append_semantic_index_to_table(struct dxil_psv_sem_index_table *table, uint32_t index, + uint32_t num_rows) +{ + if (num_rows == 1) { + for (unsigned i = 0; i < table->size; ++i) { + if (table->data[i] == index) + return i; + } + } + uint32_t retval = table->size; + assert(table->size + num_rows <= 80); + for (unsigned i = 0; i < num_rows; ++i) + table->data[table->size++] = index + i; + return retval; +} + +static const struct dxil_mdnode * +fill_SV_param_nodes(struct dxil_module *mod, unsigned record_id, + struct semantic_info *semantic) { + + const struct dxil_mdnode *SV_params_nodes[11]; + /* For this to always work we should use vectorize_io, but for FS out and VS in + * this is not implemented globally */ + const struct dxil_mdnode *flattened_semantics[256]; + + for (unsigned i = 0; i < semantic->rows; ++i) + flattened_semantics[i] = dxil_get_metadata_int32(mod, semantic->index + i); + + SV_params_nodes[0] = dxil_get_metadata_int32(mod, (int)record_id); // Unique element ID + SV_params_nodes[1] = dxil_get_metadata_string(mod, semantic->name); // Element name + SV_params_nodes[2] = dxil_get_metadata_int8(mod, semantic->sig_comp_type); // Element type + SV_params_nodes[3] = dxil_get_metadata_int8(mod, (int8_t)semantic->kind); // Effective system value + SV_params_nodes[4] = dxil_get_metadata_node(mod, flattened_semantics, + semantic->rows); // Semantic index vector + SV_params_nodes[5] = dxil_get_metadata_int8(mod, semantic->interpolation); // Interpolation mode + SV_params_nodes[6] = dxil_get_metadata_int32(mod, semantic->rows); // Number of rows + SV_params_nodes[7] = dxil_get_metadata_int8(mod, semantic->cols); // Number of columns + SV_params_nodes[8] = dxil_get_metadata_int32(mod, semantic->start_row); // Element packing start row + SV_params_nodes[9] = dxil_get_metadata_int8(mod, semantic->start_col); // Element packing start column + SV_params_nodes[10] = 0; // optional Metadata + + return dxil_get_metadata_node(mod, SV_params_nodes, ARRAY_SIZE(SV_params_nodes)); +} + +static void +fill_signature_element(struct dxil_signature_element *elm, + struct semantic_info *semantic, + unsigned row) +{ + memset(elm, 0, sizeof(struct dxil_signature_element)); + // elm->stream = 0; + // elm->semantic_name_offset = 0; // Offset needs to be filled out when writing + elm->semantic_index = semantic->index + row; + elm->system_value = (uint32_t) prog_semantic_from_kind(semantic->kind); + elm->comp_type = (uint32_t) semantic->comp_type; + elm->reg = semantic->start_row + row; + + assert(semantic->cols + semantic->start_col <= 4); + elm->mask = (uint8_t) (((1 << semantic->cols) - 1) << semantic->start_col); + // elm->never_writes_mask = 0; + elm->min_precision = DXIL_MIN_PREC_DEFAULT; +} + +static bool +fill_psv_signature_element(struct dxil_psv_signature_element *psv_elm, + struct semantic_info *semantic, struct dxil_module *mod) +{ + memset(psv_elm, 0, sizeof(struct dxil_psv_signature_element)); + psv_elm->rows = semantic->rows; + if (semantic->start_row >= 0) { + assert(semantic->start_row < 256); + psv_elm->start_row = semantic->start_row; + psv_elm->cols_and_start = (1u << 6) | (semantic->start_col << 4) | semantic->cols; + } else { + /* The validation expects that the the start row is not egative + * and apparently the extra bit in the cols_and_start indicates that the + * row is meant literally, so don't set it in this case. + * (Source of information: Comparing with the validation structures + * created by dxcompiler) + */ + psv_elm->start_row = 0; + psv_elm->cols_and_start = (semantic->start_col << 4) | semantic->cols; + } + psv_elm->semantic_kind = (uint8_t)semantic->kind; + psv_elm->component_type = semantic->comp_type; //`?? + psv_elm->interpolation_mode = semantic->interpolation; + /* to be filled later + psv_elm->dynamic_mask_and_stream = 0; + */ + if (semantic->kind == DXIL_SEM_ARBITRARY && strlen(semantic->name)) { + psv_elm->semantic_name_offset = + copy_semantic_name_to_string(mod->sem_string_table, semantic->name); + + /* TODO: clean up memory */ + if (psv_elm->semantic_name_offset == (uint32_t)-1) + return false; + } + + psv_elm->semantic_indexes_offset = + append_semantic_index_to_table(&mod->sem_index_table, semantic->index, semantic->rows); + + return true; +} + +static bool +fill_io_signature(struct dxil_module *mod, int id, + struct semantic_info *semantic, + const struct dxil_mdnode **io, + struct dxil_signature_element *elm, + struct dxil_psv_signature_element *psv_elm) +{ + + *io = fill_SV_param_nodes(mod, id, semantic); + for (unsigned i = 0; i < semantic->rows; ++i) + fill_signature_element(&elm[i], semantic, i); + return fill_psv_signature_element(psv_elm, semantic, mod); +} + +static unsigned +get_input_signature_group(struct dxil_module *mod, const struct dxil_mdnode **inputs, + unsigned num_inputs, + nir_shader *s, nir_variable_mode modes, + semantic_info_proc get_semantics, unsigned *row_iter, + bool is_gs_shader) +{ + nir_foreach_variable_with_modes(var, s, modes) { + struct semantic_info semantic = {0}; + get_semantics(var, &semantic); + mod->inputs[num_inputs].sysvalue = semantic.sysvalue_name; + *row_iter = get_additional_semantic_info(var, &semantic, *row_iter, is_gs_shader); + + mod->inputs[num_inputs].name = ralloc_strdup(mod->ralloc_ctx, + semantic.name); + mod->inputs[num_inputs].num_elements = semantic.rows; + struct dxil_signature_element *elm = mod->inputs[num_inputs].elements; + struct dxil_psv_signature_element *psv_elm = &mod->psv_inputs[num_inputs]; + + if (!fill_io_signature(mod, num_inputs, &semantic, + &inputs[num_inputs], elm, psv_elm)) + return 0; + + ++num_inputs; + assert(num_inputs < VARYING_SLOT_MAX); + } + return num_inputs; +} + +static const struct dxil_mdnode * +get_input_signature(struct dxil_module *mod, nir_shader *s) +{ + if (s->info.stage == MESA_SHADER_KERNEL) + return NULL; + + const struct dxil_mdnode *inputs[VARYING_SLOT_MAX]; + unsigned next_row = 0; + bool is_gs_shader = s->info.stage == MESA_SHADER_GEOMETRY; + + mod->num_sig_inputs = get_input_signature_group(mod, inputs, 0, + s, nir_var_shader_in, + s->info.stage == MESA_SHADER_VERTEX ? + get_semantic_vs_in_name : + (s->info.stage == MESA_SHADER_GEOMETRY ? + get_semantic_gs_in_name : get_semantic_in_name), + &next_row, is_gs_shader); + + mod->num_sig_inputs = get_input_signature_group(mod, inputs, mod->num_sig_inputs, + s, nir_var_system_value, + get_semantic_sv_name, + &next_row, is_gs_shader); + + if (!mod->num_sig_inputs && !mod->num_sig_inputs) + return NULL; + + mod->num_psv_inputs = next_row; + + const struct dxil_mdnode *retval = mod->num_sig_inputs ? + dxil_get_metadata_node(mod, inputs, mod->num_sig_inputs) : NULL; + + return retval; +} + +static const char *out_sysvalue_name(nir_variable *var) +{ + switch (var->data.location) { + case VARYING_SLOT_FACE: + return "FACE"; + case VARYING_SLOT_POS: + return "POS"; + case VARYING_SLOT_CLIP_DIST0: + case VARYING_SLOT_CLIP_DIST1: + return "CLIPDST"; + case VARYING_SLOT_PRIMITIVE_ID: + return "PRIMID"; + default: + return "NO"; + } +} + +static const struct dxil_mdnode * +get_output_signature(struct dxil_module *mod, nir_shader *s) +{ + const struct dxil_mdnode *outputs[VARYING_SLOT_MAX]; + unsigned num_outputs = 0; + unsigned next_row = 0; + nir_foreach_variable_with_modes(var, s, nir_var_shader_out) { + struct semantic_info semantic = {0}; + + if (s->info.stage == MESA_SHADER_FRAGMENT) { + get_semantic_ps_outname(var, &semantic); + mod->outputs[num_outputs].sysvalue = "TARGET"; + } else { + get_semantic_name(var, &semantic, var->type); + mod->outputs[num_outputs].sysvalue = out_sysvalue_name(var); + } + next_row = get_additional_semantic_info(var, &semantic, next_row, false); + + mod->info.has_out_position |= semantic.kind== DXIL_SEM_POSITION; + mod->info.has_out_depth |= semantic.kind == DXIL_SEM_DEPTH; + + mod->outputs[num_outputs].name = ralloc_strdup(mod->ralloc_ctx, + semantic.name); + mod->outputs[num_outputs].num_elements = semantic.rows; + struct dxil_signature_element *elm = mod->outputs[num_outputs].elements; + + struct dxil_psv_signature_element *psv_elm = &mod->psv_outputs[num_outputs]; + + if (!fill_io_signature(mod, num_outputs, &semantic, + &outputs[num_outputs], elm, psv_elm)) + return NULL; + + /* This is fishy, logic suggests that the LHS should be 0xf, but from the + * validation it needs to be 0xff */ + elm->never_writes_mask = 0xff & ~elm->mask; + + ++num_outputs; + + if (!is_depth_output(semantic.kind)) + ++mod->num_psv_outputs; + + assert(num_outputs < ARRAY_SIZE(outputs)); + } + + if (!num_outputs) + return NULL; + + const struct dxil_mdnode *retval = dxil_get_metadata_node(mod, outputs, num_outputs); + mod->num_sig_outputs = num_outputs; + return retval; +} + +const struct dxil_mdnode * +get_signatures(struct dxil_module *mod, nir_shader *s) +{ + /* DXC does the same: Add an empty string before everything else */ + mod->sem_string_table = _mesa_string_buffer_create(mod->ralloc_ctx, 1024); + copy_semantic_name_to_string(mod->sem_string_table, ""); + + const struct dxil_mdnode *input_signature = get_input_signature(mod, s); + const struct dxil_mdnode *output_signature = get_output_signature(mod, s); + + const struct dxil_mdnode *SV_nodes[3] = { + input_signature, + output_signature, + NULL + }; + if (output_signature || input_signature) + return dxil_get_metadata_node(mod, SV_nodes, ARRAY_SIZE(SV_nodes)); + else + return NULL; +} diff --git a/src/microsoft/compiler/dxil_signature.h b/src/microsoft/compiler/dxil_signature.h new file mode 100644 index 00000000000..2ecd7151a1f --- /dev/null +++ b/src/microsoft/compiler/dxil_signature.h @@ -0,0 +1,161 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in 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: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 AUTHORS 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 + * IN THE SOFTWARE. + */ + +#ifndef DXIL_SIGNATURE_H +#define DXIL_SIGNATURE_H + +#include "dxil_enums.h" +#include "nir.h" +#include "util/string_buffer.h" + +/* struct taken from DXILContainer + * Enums values were replaced by uint32_t since the must occupy 32 bit + */ + +struct dxil_signature_element { + uint32_t stream; // Stream index (parameters must appear in non-decreasing stream order) + uint32_t semantic_name_offset; // Offset to char * stream from start of DxilProgramSignature. + uint32_t semantic_index; // Semantic Index + uint32_t system_value; // Semantic type. Similar to DxilSemantic::Kind, but a serialized rather than processing rep. + uint32_t comp_type; // Type of bits. + uint32_t reg; // Register Index (row index) + uint8_t mask; // Mask (column allocation) + union { // Unconditional cases useful for validation of shader linkage. + uint8_t never_writes_mask; // For an output signature, the shader the signature belongs to never + // writes the masked components of the output register. + uint8_t always_reads_mask; // For an input signature, the shader the signature belongs to always + // reads the masked components of the input register. + }; + uint16_t pad; + uint32_t min_precision; // Minimum precision of input/output data +}; + +struct dxil_signature_record { + struct dxil_signature_element elements[32]; + unsigned num_elements; + const char *sysvalue; + char *name; +}; + +struct dxil_psv_sem_index_table { + uint32_t data[80]; + uint32_t size; +}; + +struct dxil_psv_signature_element { + uint32_t semantic_name_offset; // Offset into StringTable + uint32_t semantic_indexes_offset; // Offset into PSVSemanticIndexTable, count == Rows + uint8_t rows; // Number of rows this element occupies + uint8_t start_row; // Starting row of packing location if allocated + uint8_t cols_and_start; // 0:4 = Cols, 4:6 = StartCol, 6:7 == Allocated + uint8_t semantic_kind; // PSVSemanticKind + uint8_t component_type; // DxilProgramSigCompType + uint8_t interpolation_mode; // DXIL::InterpolationMode or D3D10_SB_INTERPOLATION_MODE + uint8_t dynamic_mask_and_stream; // 0:4 = DynamicIndexMask, 4:6 = OutputStream (0-3) + uint8_t reserved; +}; + +struct dxil_vs_info { + char output_position_present; +}; + +struct dxil_gs_info { + uint32_t input_primitive; + uint32_t output_toplology; + uint32_t output_stream_mask; + char output_position_present; +}; + +struct dxil_ps_info { + char depth_output; + char sample_frequency; +}; + +/* Maximum sized defining the union size (MSInfo)*/ +struct dxil_max_sized_info { + uint32_t dummy1[3]; + uint16_t dummy2[2]; +}; + +struct dxil_psv_runtime_info_0 { + union { + struct dxil_vs_info vs; + struct dxil_gs_info gs; + struct dxil_ps_info ps; + struct dxil_max_sized_info dummy; + }; + uint32_t min_expected_wave_lane_count; // minimum lane count required, 0 if unused + uint32_t max_expected_wave_lane_count; // maximum lane count required, 0xffffffff if unused +}; + +struct dxil_psv_runtime_info_1 { + struct dxil_psv_runtime_info_0 psv0; + uint8_t shader_stage; // PSVShaderKind + uint8_t uses_view_id; + union { + uint16_t max_vertex_count; // MaxVertexCount for GS only (max 1024) + uint8_t sig_patch_const_or_prim_vectors; // Output for HS; Input for DS; Primitive output for MS (overlaps MS1::SigPrimVectors) + // struct { uint8_t dummy[2]; } fill; + }; + + // PSVSignatureElement counts + uint8_t sig_input_elements; + uint8_t sig_output_elements; + uint8_t sig_patch_const_or_prim_elements; + + // Number of packed vectors per signature + uint8_t sig_input_vectors; + uint8_t sig_output_vectors[4]; +}; + +struct dxil_pipe_state_validation { + unsigned val_major, val_minor; + uint32_t version; + uint32_t resource_count; + uint8_t shader_stage; + struct _mesa_string_buffer *string_table; + struct dxil_psv_sem_index_table semantic_index_table; + uint8_t uses_view_id; + uint8_t sig_input_elements; + uint8_t sig_output_elements; + uint8_t sig_patch_const_or_prim_elements; + uint8_t sig_input_vectors; + uint8_t sig_patch_const_or_prim_vectors; + uint8_t sig_output_vectors[4]; +}; + +struct dxil_mdnode; +struct dxil_module; + +#ifdef __cplusplus +extern "C" { +#endif + +const struct dxil_mdnode * +get_signatures(struct dxil_module *mod, nir_shader *s); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/microsoft/compiler/meson.build b/src/microsoft/compiler/meson.build new file mode 100644 index 00000000000..17caed47361 --- /dev/null +++ b/src/microsoft/compiler/meson.build @@ -0,0 +1,57 @@ +# Copyright © Microsoft Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in 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: + +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. + +# 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 AUTHORS 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 +# IN THE SOFTWARE. + +files_libdxil_compiler = files( + 'dxil_buffer.c', + 'dxil_container.c', + 'dxil_dump.c', + 'dxil_enums.c', + 'dxil_function.c', + 'dxil_module.c', + 'dxil_signature.c', +) + +libdxil_compiler = static_library( + 'dxil_compiler', + [files_libdxil_compiler, sha1_h], + include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_compiler, inc_gallium], + dependencies: [idep_nir_headers], + gnu_symbol_visibility : 'hidden', +) + +idep_libdxil_compiler = declare_dependency( + link_with : libdxil_compiler, + dependencies : [idep_mesautil], + include_directories : include_directories('.') +) + +if with_tests + test( + 'dxil_buffer', + executable( + 'dxil_buffer_test', + files('dxil_buffer_test.c'), + include_directories : [inc_src], + dependencies : [idep_libdxil_compiler] + ), + suite: 'd3d12' + ) +endif diff --git a/src/microsoft/meson.build b/src/microsoft/meson.build new file mode 100644 index 00000000000..8bbb8ac74cb --- /dev/null +++ b/src/microsoft/meson.build @@ -0,0 +1,22 @@ +# Copyright © Microsoft Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in 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: + +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. + +# 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 AUTHORS 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 +# IN THE SOFTWARE. + +subdir('compiler')