Signed-off-by: Christian Gmeiner <christian.gmei...@gmail.com> --- src/etnaviv/compiler/eir.c | 239 ++++++++++ src/etnaviv/compiler/eir.h | 499 ++++++++++++++++++++ src/etnaviv/compiler/eir_uniform.c | 108 +++++ src/etnaviv/compiler/meson.build | 38 ++ src/etnaviv/compiler/tests/eir_assemble.cpp | 114 +++++ src/etnaviv/compiler/tests/eir_uniform.cpp | 324 +++++++++++++ src/etnaviv/compiler/tests/meson.build | 44 ++ src/etnaviv/meson.build | 1 + 8 files changed, 1367 insertions(+) create mode 100644 src/etnaviv/compiler/eir.c create mode 100644 src/etnaviv/compiler/eir.h create mode 100644 src/etnaviv/compiler/eir_uniform.c create mode 100644 src/etnaviv/compiler/meson.build create mode 100644 src/etnaviv/compiler/tests/eir_assemble.cpp create mode 100644 src/etnaviv/compiler/tests/eir_uniform.cpp create mode 100644 src/etnaviv/compiler/tests/meson.build
diff --git a/src/etnaviv/compiler/eir.c b/src/etnaviv/compiler/eir.c new file mode 100644 index 00000000000..398ae7443c5 --- /dev/null +++ b/src/etnaviv/compiler/eir.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2018 Etnaviv Project + * Copyright (C) 2018 Zodiac Inflight Innovations + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + * + * Authors: + * Christian Gmeiner <christian.gmei...@gmail.com> + */ + +#include "eir.h" +#include <stdlib.h> +#include <string.h> +#include "util/ralloc.h" + +struct eir * +eir_create(void) +{ + struct eir *ir = rzalloc(NULL, struct eir); + + list_inithead(&ir->block_list); + util_dynarray_init(&ir->reg_alloc, ir); + util_dynarray_init(&ir->uniform_alloc, ir); + + return ir; +} + +void +eir_destroy(struct eir *ir) +{ + assert(ir); + util_dynarray_fini(&ir->reg_alloc); + util_dynarray_fini(&ir->uniform_alloc); + ralloc_free(ir); +} + +struct eir_block * +eir_block_create(struct eir *ir) +{ + assert(ir); + struct eir_block *block = rzalloc(ir, struct eir_block); + + block->ir = ir; + block->num = ir->blocks++; + list_inithead(&block->node); + list_inithead(&block->instr_list); + + list_addtail(&block->node, &ir->block_list); + + return block; +} + +struct eir_instruction * +eir_instruction_create(struct eir_block *block, enum gc_op opc) +{ + assert(block); + struct eir_instruction *instr = rzalloc(block, struct eir_instruction); + + instr->block = block; + list_addtail(&instr->node, &block->instr_list); + + instr->gc.opcode = opc; + + return instr; +} + +struct eir_register +eir_temp_register(struct eir *ir, unsigned num_components) +{ + assert(num_components >= 1 && num_components <= 4); + + struct eir_register reg = { + .type = EIR_REG_TEMP, + .index = util_dynarray_num_elements(&ir->reg_alloc, unsigned), + }; + + util_dynarray_append(&ir->reg_alloc, unsigned, num_components); + + return reg; +} + +void +eir_link_blocks(struct eir_block *predecessor, struct eir_block *successor) +{ + assert(predecessor); + assert(successor); + + if (predecessor->successors[0]) { + assert(!predecessor->successors[1]); + predecessor->successors[1] = successor; + } else { + predecessor->successors[0] = successor; + } +} + +static void +convert_sampler(const struct eir_register *eir, struct gc_instr_sampler *sampler) +{ + assert(eir->type == EIR_REG_SAMPLER); + + sampler->id = eir->index; + sampler->swiz = eir->swizzle; + sampler->amode = GC_ADDRESSING_MODE_DIRECT; +} + +static void +convert_src(const struct eir_register *eir, struct gc_instr_src *gc) +{ + assert(!gc->use); + assert(eir->type != EIR_REG_UNDEF); + assert(eir->type != EIR_REG_SAMPLER); + + gc->use = true; + gc->reg = eir->index; + gc->abs = eir->abs; + gc->neg = eir->neg; + gc->swiz = eir->swizzle; + + switch (eir->type) { + case EIR_REG_TEMP: + gc->rgroup = GC_REGISTER_GROUP_TEMP; + break; + + case EIR_REG_UNIFORM: + gc->rgroup = GC_REGISTER_GROUP_UNIFORM; + break; + + default: + unreachable("unhandled type"); + } +} + +static void +convert_dst(const struct eir_register *eir, struct gc_instr_dst *gc) +{ + assert(!gc->comps); + + gc->reg = eir->index; + gc->comps = eir->writemask; +} + +static void +eir_to_gc(struct eir_instruction *instr) +{ + struct gc_instr *gc = &instr->gc; + + if (gc_op_num_src(gc->opcode)) { + const unsigned swizzle = gc_op_src_swizzle(gc->opcode); + + /* src swizzle */ + for (int i = 0; i < gc_op_num_src(gc->opcode); i++) { + const unsigned shift = i * 2; + const unsigned mask = 0x3 << shift; + const unsigned index = (swizzle & mask) >> shift; + + if (index == 0x3) + continue; + + if (instr->src[i].type == EIR_REG_UNDEF) + continue; + + switch (gc->type) { + case GC_OP_TYPE_ALU: + convert_src(&instr->src[i], &gc->alu.src[index]); + break; + + case GC_OP_TYPE_BRANCH: + convert_src(&instr->src[i], &gc->branch.src[index]); + break; + + case GC_OP_TYPE_SAMPLER: + if (i == 0) + convert_sampler(&instr->src[0], &gc->sampler); + else if (i == 1) + convert_src(&instr->src[1], &gc->sampler.src); + else + unreachable("unkown sampler index"); + + break; + } + } + + /* special handling for src replication */ + if (gc->type == GC_OP_TYPE_ALU && swizzle & SWIZ_REP_SRC0_TO_SRC2) { + assert(gc->type == GC_OP_TYPE_ALU); + convert_src(&instr->src[0], &gc->alu.src[2]); + } + } + + if (gc_op_has_dst(gc->opcode)) + convert_dst(&instr->dst, &gc->dst); +} + +uint32_t * +eir_assemble(const struct eir *ir, struct eir_info *info) +{ + assert(ir); + assert(info); + uint32_t *ptr, *dwords; + + memset(info, 0, sizeof(*info)); + + eir_for_each_block(block, ir) { + eir_for_each_inst(instr, block) { + info->sizedwords += 4; + } + } + + ptr = dwords = calloc(4, info->sizedwords); + if (!ptr) + return NULL; + + eir_for_each_block(block, ir) { + eir_for_each_inst(instr, block) { + eir_to_gc(instr); + gc_pack_instr(&instr->gc, dwords); + dwords += 4; + } + } + + return ptr; +} diff --git a/src/etnaviv/compiler/eir.h b/src/etnaviv/compiler/eir.h new file mode 100644 index 00000000000..e2185b004f1 --- /dev/null +++ b/src/etnaviv/compiler/eir.h @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2018 Etnaviv Project + * Copyright (C) 2018 Zodiac Inflight Innovations + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + * + * Authors: + * Christian Gmeiner <christian.gmei...@gmail.com> + */ + +#ifndef H_EIR +#define H_EIR + +#include <assert.h> +#include "util/list.h" +#include "util/u_dynarray.h" +#include "util/u_math.h" +#include "etnaviv/gc/gc_instr.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +struct eir; +struct eir_block; + +struct eir_register +{ + enum { + EIR_REG_UNDEF = 0, + EIR_REG_TEMP, + EIR_REG_UNIFORM, + EIR_REG_SAMPLER, + } type; + + unsigned index; + + /* dst only: */ + unsigned writemask:4; + /* src only: */ + unsigned swizzle:8; + unsigned abs:1; + unsigned neg:1; +}; + +struct eir_instruction +{ + struct eir_block *block; + struct list_head node; /* entry in eir_block's instruction list */ + + /* Pre-register-allocation references to src/dst registers */ + struct eir_register dst; + struct eir_register src[3]; + + struct gc_instr gc; /* instruction being wrapped. */ +}; + +struct eir_block +{ + struct eir *ir; + struct list_head node; /* entry in eir's block list */ + struct list_head instr_list; + + unsigned num; + + struct eir_block *successors[2]; + + /* per-pass extra block data */ + void *data; +}; + +enum eir_uniform_contents +{ + EIR_UNIFORM_UNUSED, + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_IMAGE_WIDTH, + EIR_UNIFORM_IMAGE_HEIGHT, + EIR_UNIFORM_IMAGE_DEPTH, +}; + +static inline const char * +eir_uniform_content(enum eir_uniform_contents content) +{ + switch(content) { + case EIR_UNIFORM_UNUSED: + return "unused"; + case EIR_UNIFORM_CONSTANT: + return "constant"; + case EIR_UNIFORM_IMAGE_WIDTH: + return "image width"; + case EIR_UNIFORM_IMAGE_HEIGHT: + return "image height"; + case EIR_UNIFORM_IMAGE_DEPTH: + return "image depth"; + default: + unreachable("unhandled content type"); + break; + } + + return NULL; +} + +struct eir_uniform_data +{ + enum eir_uniform_contents content; + uint32_t data; +}; + +struct eir +{ + struct list_head block_list; + unsigned blocks; + + /* attributes/varyings: */ + unsigned num_inputs; + struct { + unsigned slot; + unsigned reg; + unsigned ncomp; + } inputs[16]; + + /* varyings/outputs: */ + unsigned num_outputs; + struct { + unsigned slot; + unsigned reg; + unsigned ncomp; + } outputs[16]; + + /* keep track of numer of allocated registers + * and the used components per register */ + struct util_dynarray reg_alloc; + + /* keep track of number of allocated uniforms */ + struct util_dynarray uniform_alloc; + unsigned uniform_offset; +}; + +struct eir_info { + uint16_t sizedwords; +}; + +struct eir * +eir_create(void); + +void +eir_destroy(struct eir *ir); + +struct eir_block * +eir_block_create(struct eir *ir); + +struct eir_instruction * +eir_instruction_create(struct eir_block *block, enum gc_op opc); + +struct eir_register +eir_temp_register(struct eir *ir, unsigned num_components); + +struct eir_register +eir_uniform_register_vec4(struct eir *ir, + const unsigned ncomp, + const enum eir_uniform_contents *contents, + const uint32_t *values); + +static inline struct eir_register +eir_uniform_register(struct eir *ir, const enum eir_uniform_contents content, uint32_t value) +{ + const enum eir_uniform_contents contents[] = { + content + }; + + const uint32_t values[] = { + value + }; + + return eir_uniform_register_vec4(ir, 1, contents, values); +} + +static inline struct eir_register +eir_uniform_register_ui(struct eir *ir, uint32_t value) +{ + static const enum eir_uniform_contents contents[] = { + EIR_UNIFORM_CONSTANT + }; + + uint32_t values[] = { + value + }; + + return eir_uniform_register_vec4(ir, 1, contents, values); +} + +static inline struct eir_register +eir_uniform_register_f(struct eir *ir, float value) +{ + static const enum eir_uniform_contents contents[] = { + EIR_UNIFORM_CONSTANT + }; + + uint32_t values[] = { + fui(value) + }; + + return eir_uniform_register_vec4(ir, 1, contents, values); +} + +static inline struct eir_register +eir_uniform_register_vec4_ui(struct eir *ir, const unsigned ncomp, const uint32_t *values) +{ + static const enum eir_uniform_contents contents[] = + { + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_CONSTANT, + }; + + return eir_uniform_register_vec4(ir, ncomp, contents, values); +} + +static inline struct eir_register +eir_uniform_register_vec4_f(struct eir *ir, const unsigned ncomp, float *values) +{ + static const enum eir_uniform_contents contents[] = + { + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_CONSTANT, + }; + + uint32_t val[4]; + + for (unsigned i = 0; i < ncomp; i++) + val[i] = fui(values[i]); + + return eir_uniform_register_vec4(ir, ncomp, contents, val); +} + +void +eir_link_blocks(struct eir_block *predecessor, struct eir_block *successor); + +static inline void +eir_assign_input(struct eir *ir, unsigned idx, unsigned slot, unsigned ncomp) +{ + assert(ir); + assert(idx < ARRAY_SIZE(ir->inputs)); + + ir->inputs[idx].reg = idx; + ir->inputs[idx].slot = slot; + ir->inputs[idx].ncomp = ncomp; + + ir->num_inputs = MAX2(ir->num_inputs, idx + 1); +} + +static inline void +eir_assign_output(struct eir *ir, unsigned idx, unsigned slot, unsigned ncomp) +{ + assert(ir); + assert(idx < ARRAY_SIZE(ir->outputs)); + + ir->outputs[idx].reg = idx; + ir->outputs[idx].slot = slot; + ir->outputs[idx].ncomp = ncomp; + + ir->num_outputs = MAX2(ir->num_outputs, idx + 1); +} + +void +eir_calculate_live_intervals(struct eir *ir); + +int +eir_temp_range_start(const struct eir* ir, unsigned n); + +int +eir_temp_range_end(const struct eir* ir, unsigned n); + +uint32_t * +eir_assemble(const struct eir *ir, struct eir_info *info); + +static inline struct eir_instruction * +eir_SET(struct eir_block *block, struct eir_register *dst, + struct eir_register *src0, enum gc_cond condition, + struct eir_register *src1) +{ + struct eir_instruction *instr; + + assert(gc_op_has_dst(GC_SET)); + assert(gc_op_num_src(GC_SET) == 2); + + instr = eir_instruction_create(block, GC_SET); + instr->gc.type = GC_OP_TYPE_ALU; + instr->gc.condition = condition; + instr->dst = *dst; + instr->src[0] = *src0; + instr->src[1] = *src1; + + return instr; +} + +static inline struct eir_instruction * +eir_BRANCH(struct eir_block *block, struct eir_register *src0, + struct eir_register *src1) +{ + struct eir_instruction *instr; + + assert(!gc_op_has_dst(GC_BRANCH)); + assert(gc_op_num_src(GC_BRANCH) == 2); + + instr = eir_instruction_create(block, GC_BRANCH); + instr->gc.type = GC_OP_TYPE_BRANCH; + instr->gc.branch.imm = ~0; + instr->src[0] = *src0; + instr->src[1] = *src1; + + return instr; +} + +static inline struct eir_instruction * +eir_TEXKILL_IF(struct eir_block *block, struct eir_register *src0, + enum gc_cond condition, struct eir_register *src1) +{ + struct eir_instruction *instr; + + assert(!gc_op_has_dst(GC_TEXKILL_IF)); + assert(gc_op_num_src(GC_TEXKILL_IF) == 2); + + instr = eir_instruction_create(block, GC_TEXKILL_IF); + instr->gc.type = GC_OP_TYPE_ALU; + instr->gc.condition = condition; + instr->src[0] = *src0; + instr->src[1] = *src1; + + return instr; +} + +#define ALU0(opc) \ +static inline struct eir_instruction * \ +eir_##opc(struct eir_block *block) \ +{ \ + struct eir_instruction *instr; \ + \ + assert(!gc_op_has_dst(GC_##opc));\ + assert(gc_op_num_src(GC_##opc) == 0);\ + \ + instr = eir_instruction_create(block, GC_##opc); \ + instr->gc.type = GC_OP_TYPE_ALU; \ + \ + return instr; \ +} + +#define ALU1(opc) \ +static inline struct eir_instruction * \ +eir_##opc(struct eir_block *block, struct eir_register *dst, \ + struct eir_register *src0) \ +{ \ + struct eir_instruction *instr; \ + \ + assert(gc_op_has_dst(GC_##opc));\ + assert(gc_op_num_src(GC_##opc) >= 1);\ + \ + instr = eir_instruction_create(block, GC_##opc); \ + instr->gc.type = GC_OP_TYPE_ALU; \ + instr->dst = *dst; \ + instr->src[0] = *src0; \ + \ + return instr; \ +} + +#define ALU2(opc) \ +static inline struct eir_instruction * \ +eir_##opc(struct eir_block *block, struct eir_register *dst, \ + struct eir_register *src0, struct eir_register *src1) \ +{ \ + struct eir_instruction *instr; \ + \ + assert(gc_op_has_dst(GC_##opc));\ + assert(gc_op_num_src(GC_##opc) == 2);\ + \ + instr = eir_instruction_create(block, GC_##opc); \ + instr->gc.type = GC_OP_TYPE_ALU; \ + instr->dst = *dst; \ + instr->src[0] = *src0; \ + instr->src[1] = *src1; \ + \ + return instr; \ +} + +#define ALU3(opc) \ +static inline struct eir_instruction * \ +eir_##opc(struct eir_block *block, struct eir_register *dst, \ + struct eir_register *src0, struct eir_register *src1, \ + struct eir_register *src2) \ +{ \ + struct eir_instruction *instr; \ + \ + assert(gc_op_has_dst(GC_##opc));\ + assert(gc_op_num_src(GC_##opc) == 3);\ + \ + instr = eir_instruction_create(block, GC_##opc); \ + instr->gc.type = GC_OP_TYPE_ALU; \ + instr->dst = *dst; \ + instr->src[0] = *src0; \ + instr->src[1] = *src1; \ + instr->src[2] = *src2; \ + \ + return instr; \ +} + +#define TEX(opc) \ +static inline struct eir_instruction * \ +eir_##opc(struct eir_block *block, struct eir_register *dst, \ + struct eir_register *sampler, struct eir_register *src) \ +{ \ + struct eir_instruction *instr; \ + \ + assert(gc_op_has_dst(GC_##opc));\ + assert(gc_op_num_src(GC_##opc) == 2); \ + \ + instr = eir_instruction_create(block, GC_##opc); \ + instr->gc.type = GC_OP_TYPE_SAMPLER; \ + instr->dst = *dst; \ + instr->src[0] = *sampler; \ + instr->src[1] = *src; \ + \ + return instr; \ +} + +ALU0(NOP); +ALU0(TEXKILL); + +ALU1(MOV); +ALU1(MOVAR); +ALU1(RCP); +ALU1(RSQ); +ALU1(CEIL); +ALU1(FLOOR); +ALU1(FRC); +ALU1(LOG); +ALU1(SQRT); +ALU1(SIN); +ALU1(COS); +ALU1(EXP); +ALU1(DSX); +ALU1(DSY); + +ALU2(ADD); +ALU2(MUL); +ALU2(DP2); +ALU2(DP3); +ALU2(DP4); + +ALU3(MAD); +ALU3(SELECT); + +TEX(TEXLD); +TEX(TEXLDB); +TEX(TEXLDL); + +#define eir_for_each_block(block, ir) \ + list_for_each_entry(struct eir_block, block, &ir->block_list, node) + +#define eir_for_each_block_rev(block, ir) \ + list_for_each_entry_rev(struct eir_block, block, &ir->block_list, node) + +/* Loop over the non-NULL members of the successors array. */ +#define eir_for_each_successor(succ, block) \ + for (struct eir_block *succ = block->successors[0]; \ + succ != NULL; \ + succ = (succ == block->successors[1] ? NULL : \ + block->successors[1])) + +#define eir_for_each_inst(inst, block) \ + list_for_each_entry(struct eir_instruction, inst, &block->instr_list, node) + +#define eir_for_each_inst_safe(inst, block) \ + list_for_each_entry_safe(struct eir_instruction, inst, &block->instr_list, node) + +#ifdef __cplusplus +} +#endif + +#endif // H_EIR diff --git a/src/etnaviv/compiler/eir_uniform.c b/src/etnaviv/compiler/eir_uniform.c new file mode 100644 index 00000000000..7f75215e480 --- /dev/null +++ b/src/etnaviv/compiler/eir_uniform.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018 Etnaviv Project + * Copyright (C) 2018 Zodiac Inflight Innovations + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + * + * Authors: + * Christian Gmeiner <christian.gmei...@gmail.com> + */ + +#include "eir.h" + +static inline void +append_uniform(struct eir *ir, enum eir_uniform_contents content, uint32_t value) +{ + struct eir_uniform_data d = { + .content = content, + .data = value + }; + + util_dynarray_append(&ir->uniform_alloc, struct eir_uniform_data, d); +} + +struct eir_register +eir_uniform_register_vec4(struct eir *ir, + const unsigned ncomp, + const enum eir_uniform_contents *contents, + const uint32_t *values) +{ + const unsigned size = util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data); + unsigned idx, i; + + /* is there already something useful to reuse? */ + for (idx = 0; idx < size; idx++) { + const struct eir_uniform_data *data; + + for (i = 0; i < ncomp; i++) { + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, idx + i); + + if (data->content == EIR_UNIFORM_UNUSED) + continue; + + if (data->content != contents[i] || data->data != values[i]) + break; + } + + /* matched all components */ + if (i == ncomp) + break; + } + + /* do we need to update unused items? */ + if (idx != size) { + struct eir_uniform_data *data; + + for (i = 0; i < ncomp; i++) { + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, idx + i); + + data->content = contents[i]; + data->data = values[i]; + } + } + + /* need to allocate new immediate */ + if (idx == size) { + /* pad out current uniform vector - if needed */ + if (size % 4) + for (i = size % 4; i < ncomp; i++) + append_uniform(ir, EIR_UNIFORM_UNUSED, 0); + + for (i = 0; i < ncomp; i++) + append_uniform(ir, contents[i], values[i]); + + idx = util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data); + idx -= ncomp; + } + + idx += ir->uniform_offset; + + struct eir_register reg = { + .type = EIR_REG_UNIFORM, + .index = idx / 4, + }; + + if (ncomp == 4) + reg.swizzle = INST_SWIZ_IDENTITY; + else + reg.swizzle = INST_SWIZ_BROADCAST(idx & 3); + + return reg; +} diff --git a/src/etnaviv/compiler/meson.build b/src/etnaviv/compiler/meson.build new file mode 100644 index 00000000000..8affe6ebd48 --- /dev/null +++ b/src/etnaviv/compiler/meson.build @@ -0,0 +1,38 @@ +# Copyright (c) 2018 Etnaviv Project +# Copyright (C) 2018 Zodiac Inflight Innovations +# +# 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, sub license, +# 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 NON-INFRINGEMENT. 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. + +libetnaviv_compiler_files = files( + 'eir.c', + 'eir.h', + 'eir_uniform.c', +) + +libetnaviv_compiler = static_library( + ['etnaviv_compiler'], + libetnaviv_compiler_files, + include_directories : [inc_common, inc_etnaviv], + c_args : [c_vis_args, no_override_init_args], + dependencies : [dep_libdrm, dep_valgrind, idep_nir], + build_by_default : true, +) + +subdir('tests') diff --git a/src/etnaviv/compiler/tests/eir_assemble.cpp b/src/etnaviv/compiler/tests/eir_assemble.cpp new file mode 100644 index 00000000000..63535908a32 --- /dev/null +++ b/src/etnaviv/compiler/tests/eir_assemble.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018 Etnaviv Project + * Copyright (C) 2018 Zodiac Inflight Innovations + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + * + * Authors: + * Christian Gmeiner <christian.gmei...@gmail.com> + */ + +#include <gtest/gtest.h> +#include "etnaviv/compiler/eir.h" + +TEST (AssembleTest, NopAssembleDisassemble) +{ + struct eir *ir = eir_create(); + struct eir_block *block = eir_block_create(ir); + + eir_NOP(block); + + struct eir_info info; + void *bin = eir_assemble(ir, &info); + ASSERT_TRUE(bin); + + eir_destroy(ir); + + struct gc_instr instr; + gc_unpack_instr((uint32_t* )bin, &instr); + + ASSERT_EQ(instr.type, GC_OP_TYPE_ALU); + ASSERT_EQ(instr.opcode, GC_NOP); + + ASSERT_EQ(info.sizedwords, 4); + + free(bin); +} + +TEST (AssembleTest, Swizzle) +{ + struct eir *ir = eir_create(); + struct eir_block *block = eir_block_create(ir); + + struct eir_register d = eir_temp_register(ir, 4); + struct eir_register s0 = eir_temp_register(ir, 4); + struct eir_register s1 = eir_temp_register(ir, 4); + + eir_ADD(block, &d, &s0, &s1); + + struct eir_info info; + void *bin = eir_assemble(ir, &info); + ASSERT_TRUE(bin); + + eir_destroy(ir); + + struct gc_instr instr; + gc_unpack_instr((uint32_t* )bin, &instr); + + ASSERT_EQ(instr.type, GC_OP_TYPE_ALU); + ASSERT_EQ(instr.opcode, GC_ADD); + ASSERT_TRUE(instr.alu.src[0].use); + ASSERT_FALSE(instr.alu.src[1].use); + ASSERT_TRUE(instr.alu.src[2].use); + ASSERT_EQ(instr.alu.src[0].reg, 1); + ASSERT_EQ(instr.alu.src[2].reg, 2); + ASSERT_EQ(instr.dst.reg, 0); + + free(bin); +} + +TEST (AssembleTest, SwizzleReplicate) +{ + struct eir *ir = eir_create(); + struct eir_block *block = eir_block_create(ir); + + struct eir_register d = eir_temp_register(ir, 4); + struct eir_register s = eir_temp_register(ir, 4); + eir_DSX(block, &d, &s); + + struct eir_info info; + void *bin = eir_assemble(ir, &info); + ASSERT_TRUE(bin); + + eir_destroy(ir); + + struct gc_instr instr; + gc_unpack_instr((uint32_t* )bin, &instr); + + ASSERT_EQ(instr.type, GC_OP_TYPE_ALU); + ASSERT_EQ(instr.opcode, GC_DSX); + ASSERT_TRUE(instr.alu.src[0].use); + ASSERT_FALSE(instr.alu.src[1].use); + ASSERT_TRUE(instr.alu.src[2].use); + ASSERT_EQ(instr.alu.src[0].reg, 1); + ASSERT_EQ(instr.alu.src[2].reg, 1); + + free(bin); +} diff --git a/src/etnaviv/compiler/tests/eir_uniform.cpp b/src/etnaviv/compiler/tests/eir_uniform.cpp new file mode 100644 index 00000000000..867e51ab384 --- /dev/null +++ b/src/etnaviv/compiler/tests/eir_uniform.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2018 Etnaviv Project + * Copyright (C) 2018 Zodiac Inflight Innovations + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + * + * Authors: + * Christian Gmeiner <christian.gmei...@gmail.com> + */ + +#include <gtest/gtest.h> +#include "etnaviv/compiler/eir.h" + +TEST (UniformTest, Basic) +{ + struct eir *ir = eir_create(); + struct eir_register u; + const struct eir_uniform_data *data; + + u = eir_uniform_register_ui(ir, 1); + + ASSERT_EQ(u.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u.index, 0); + ASSERT_EQ(u.swizzle, INST_SWIZ_BROADCAST(0)); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 0); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 1); + + eir_destroy(ir); +} + +TEST (UniformTest, ReuseUnused) +{ + struct eir *ir = eir_create(); + struct eir_register u1, u2; + + eir_uniform_register(ir, EIR_UNIFORM_UNUSED, 0); + + ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 1); + + u1 = eir_uniform_register_ui(ir, 1); + u2 = eir_uniform_register_ui(ir, 1); + + ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 1); + + ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u1.index, 0); + ASSERT_EQ(u1.swizzle, INST_SWIZ_BROADCAST(0)); + + ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u2.index, 0); + ASSERT_EQ(u2.swizzle, INST_SWIZ_BROADCAST(0)); + + eir_destroy(ir); +} + +TEST (UniformTest, ReuseUnusedCausedByVec4) +{ + struct eir *ir = eir_create(); + struct eir_register u1, u2, u3; + + u1 = eir_uniform_register_ui(ir, 0); + + ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 1); + + uint32_t v[] = { + 10, + 11, + 12, + 13, + }; + + u2 = eir_uniform_register_vec4_ui(ir, 4, v); + + ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 8); + + u3 = eir_uniform_register_ui(ir, 1); + + ASSERT_EQ(util_dynarray_num_elements(&ir->uniform_alloc, struct eir_uniform_data), 8); + + ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u1.index, 0); + ASSERT_EQ(u1.swizzle, INST_SWIZ_BROADCAST(0)); + + ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u2.index, 1); + ASSERT_EQ(u2.swizzle, INST_SWIZ_IDENTITY); + + ASSERT_EQ(u3.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u3.index, 0); + ASSERT_EQ(u3.swizzle, INST_SWIZ_BROADCAST(1)); + + eir_destroy(ir); +} + +TEST (UniformTest, EqualUniforms) +{ + struct eir *ir = eir_create(); + struct eir_register u1, u2; + + u1 = eir_uniform_register_ui(ir, 1); + u2 = eir_uniform_register_ui(ir, 1); + + ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u1.index, 0); + ASSERT_EQ(u1.swizzle, INST_SWIZ_BROADCAST(0)); + + ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u2.index, 0); + ASSERT_EQ(u2.swizzle, INST_SWIZ_BROADCAST(0)); + + eir_destroy(ir); +} + +TEST (UniformTest, MultipeSwizzles) +{ + struct eir *ir = eir_create(); + struct eir_register u1, u2, u3, u4, u5; + const struct eir_uniform_data *data; + + u1 = eir_uniform_register_ui(ir, 0); + u2 = eir_uniform_register_ui(ir, 1); + u3 = eir_uniform_register_ui(ir, 2); + u4 = eir_uniform_register_ui(ir, 3); + u5 = eir_uniform_register_ui(ir, 4); + + ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u1.index, 0); + ASSERT_EQ(u1.swizzle, INST_SWIZ_BROADCAST(0)); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 0); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 0); + + + ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u2.index, 0); + ASSERT_EQ(u2.swizzle, INST_SWIZ_BROADCAST(1)); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 1); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 1); + + + ASSERT_EQ(u3.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u3.index, 0); + ASSERT_EQ(u3.swizzle, INST_SWIZ_BROADCAST(2)); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 2); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 2); + + ASSERT_EQ(u4.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u4.index, 0); + ASSERT_EQ(u4.swizzle, INST_SWIZ_BROADCAST(3)); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 3); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 3); + + + ASSERT_EQ(u5.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u5.index, 1); + ASSERT_EQ(u5.swizzle, INST_SWIZ_BROADCAST(0)); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 4); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 4); + + eir_destroy(ir); +} + +TEST (UniformTest, BasicVec4) +{ + static const uint32_t values[4] = { 1, 2, 3, 4 }; + struct eir *ir = eir_create(); + struct eir_register u; + struct eir_uniform_data *data; + + u = eir_uniform_register_vec4_ui(ir, 4, values); + + ASSERT_EQ(u.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u.index, 0); + ASSERT_EQ(u.swizzle, INST_SWIZ_IDENTITY); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 0); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 1); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 1); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 2); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 2); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 3); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 3); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 4); + + eir_destroy(ir); +} + +TEST (UniformTest, EqualUnfiormsVec4) +{ + static const uint32_t values[4] = { 1, 2, 3, 4 }; + struct eir *ir = eir_create(); + struct eir_register u1, u2; + struct eir_uniform_data *data; + + u1 = eir_uniform_register_vec4_ui(ir, 4, values); + u2 = eir_uniform_register_vec4_ui(ir, 4, values); + + ASSERT_EQ(u1.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u1.index, 0); + ASSERT_EQ(u1.swizzle, INST_SWIZ_IDENTITY); + + ASSERT_EQ(u2.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u2.index, 0); + ASSERT_EQ(u2.swizzle, INST_SWIZ_IDENTITY); + + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 0); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 1); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 1); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 2); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 2); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 3); + + data = util_dynarray_element(&ir->uniform_alloc, struct eir_uniform_data, 3); + ASSERT_EQ(data->content, EIR_UNIFORM_CONSTANT); + ASSERT_EQ(data->data, 4); + + eir_destroy(ir); +} + +TEST (UniformTest, ncomp1) +{ + struct eir *ir = eir_create(); + + static const eir_uniform_contents contents[4] = { + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_UNUSED, + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_CONSTANT, + }; + + static const uint32_t values[4] = { + 1, + 2, + 3, + 4, + }; + + eir_uniform_register_vec4(ir, 4, contents, values); + + struct eir_register u = eir_uniform_register_ui(ir, 2); + + ASSERT_EQ(u.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u.index, 0); + ASSERT_EQ(u.swizzle, INST_SWIZ_BROADCAST(1)); +} + +TEST (UniformTest, ncomp2) +{ + struct eir *ir = eir_create(); + + static const eir_uniform_contents contents[] = { + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_UNUSED, + EIR_UNIFORM_UNUSED, + EIR_UNIFORM_CONSTANT, + }; + + static const uint32_t values[] = { + 1, + 2, + 3, + 4, + }; + + eir_uniform_register_vec4(ir, 4, contents, values); + + + static const eir_uniform_contents c[] = { + EIR_UNIFORM_CONSTANT, + EIR_UNIFORM_CONSTANT, + }; + + static const uint32_t v[] = { + 10, + 10, + }; + + struct eir_register u = eir_uniform_register_vec4(ir, 2, c, v); + + ASSERT_EQ(u.type, eir_register::EIR_REG_UNIFORM); + ASSERT_EQ(u.index, 0); + ASSERT_EQ(u.swizzle, INST_SWIZ_BROADCAST(1)); +} diff --git a/src/etnaviv/compiler/tests/meson.build b/src/etnaviv/compiler/tests/meson.build new file mode 100644 index 00000000000..c7506f04ed5 --- /dev/null +++ b/src/etnaviv/compiler/tests/meson.build @@ -0,0 +1,44 @@ +# Copyright (c) 2018 Etnaviv Project +# Copyright (C) 2018 Zodiac Inflight Innovations +# +# 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, sub license, +# 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 NON-INFRINGEMENT. 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. + +test( + 'eir_assemble', + executable( + 'eir_assemble', 'eir_assemble.cpp', + cpp_args : [cpp_vis_args, cpp_msvc_compat_args], + link_with: [libetnaviv_gc, libetnaviv_compiler, libmesa_util], + include_directories: [inc_common, inc_etnaviv], + dependencies : [dep_clock, dep_thread, idep_gtest], + ) +) + +test( + 'eir_uniform', + executable( + 'eir_uniform', 'eir_uniform.cpp', + cpp_args : [cpp_vis_args, cpp_msvc_compat_args], + link_with: [libetnaviv_gc, libetnaviv_compiler, libmesa_util], + include_directories: [inc_common, inc_etnaviv], + dependencies : [dep_clock, dep_thread, idep_gtest], + ) +) + diff --git a/src/etnaviv/meson.build b/src/etnaviv/meson.build index a706feafe86..e2a6408d7c3 100644 --- a/src/etnaviv/meson.build +++ b/src/etnaviv/meson.build @@ -23,3 +23,4 @@ inc_etnaviv = include_directories('.') subdir('gc') +subdir('compiler') -- 2.21.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev