nvc0: remove old shader backend files
This commit is contained in:
@@ -1,713 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 Christoph Bumiller
|
||||
*
|
||||
* 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 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 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 "nvc0_pc.h"
|
||||
#include "nvc0_program.h"
|
||||
|
||||
uint8_t
|
||||
nvc0_ir_reverse_cc(uint8_t cc)
|
||||
{
|
||||
static const uint8_t cc_swapped[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||
|
||||
return cc_swapped[cc & 7] | (cc & ~7);
|
||||
}
|
||||
|
||||
boolean
|
||||
nvc0_insn_can_load(struct nv_instruction *nvi, int s,
|
||||
struct nv_instruction *ld)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ld->opcode == NV_OP_MOV && ld->src[0]->value->reg.file == NV_FILE_IMM) {
|
||||
if (s > 1 || !(nvc0_op_info_table[nvi->opcode].immediate & (1 << s)))
|
||||
return FALSE;
|
||||
if (!(nvc0_op_info_table[nvi->opcode].immediate & 4))
|
||||
if (ld->src[0]->value->reg.imm.u32 & 0xfff)
|
||||
return FALSE;
|
||||
} else
|
||||
if (!(nvc0_op_info_table[nvi->opcode].memory & (1 << s)))
|
||||
return FALSE;
|
||||
|
||||
if (ld->indirect >= 0)
|
||||
return FALSE;
|
||||
|
||||
/* a few ops can use g[] sources directly, but we don't support g[] yet */
|
||||
if (ld->src[0]->value->reg.file == NV_FILE_MEM_L ||
|
||||
ld->src[0]->value->reg.file == NV_FILE_MEM_G)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < 3 && nvi->src[i]; ++i)
|
||||
if (nvi->src[i]->value->reg.file == NV_FILE_IMM)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Return whether this instruction can be executed conditionally. */
|
||||
boolean
|
||||
nvc0_insn_is_predicateable(struct nv_instruction *nvi)
|
||||
{
|
||||
if (nvi->predicate >= 0) /* already predicated */
|
||||
return FALSE;
|
||||
if (!nvc0_op_info_table[nvi->opcode].predicate &&
|
||||
!nvc0_op_info_table[nvi->opcode].pseudo)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
nvc0_insn_refcount(struct nv_instruction *nvi)
|
||||
{
|
||||
int rc = 0;
|
||||
int i;
|
||||
for (i = 0; i < 5 && nvi->def[i]; ++i) {
|
||||
if (!nvi->def[i])
|
||||
return rc;
|
||||
rc += nvi->def[i]->refc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
nvc0_pc_replace_value(struct nv_pc *pc,
|
||||
struct nv_value *old_val,
|
||||
struct nv_value *new_val)
|
||||
{
|
||||
int i, n, s;
|
||||
|
||||
if (old_val == new_val)
|
||||
return old_val->refc;
|
||||
|
||||
for (i = 0, n = 0; i < pc->num_refs; ++i) {
|
||||
if (pc->refs[i]->value == old_val) {
|
||||
++n;
|
||||
for (s = 0; s < 6 && pc->refs[i]->insn->src[s]; ++s)
|
||||
if (pc->refs[i]->insn->src[s] == pc->refs[i])
|
||||
break;
|
||||
assert(s < 6);
|
||||
nv_reference(pc, pc->refs[i]->insn, s, new_val);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static INLINE boolean
|
||||
is_gpr63(struct nv_value *val)
|
||||
{
|
||||
return (val->reg.file == NV_FILE_GPR && val->reg.id == 63);
|
||||
}
|
||||
|
||||
struct nv_value *
|
||||
nvc0_pc_find_constant(struct nv_ref *ref)
|
||||
{
|
||||
struct nv_value *src;
|
||||
|
||||
if (!ref)
|
||||
return NULL;
|
||||
|
||||
src = ref->value;
|
||||
while (src->insn && src->insn->opcode == NV_OP_MOV) {
|
||||
assert(!src->insn->src[0]->mod);
|
||||
src = src->insn->src[0]->value;
|
||||
}
|
||||
if ((src->reg.file == NV_FILE_IMM) || is_gpr63(src) ||
|
||||
(src->insn &&
|
||||
src->insn->opcode == NV_OP_LD &&
|
||||
src->insn->src[0]->value->reg.file >= NV_FILE_MEM_C(0) &&
|
||||
src->insn->src[0]->value->reg.file <= NV_FILE_MEM_C(15)))
|
||||
return src;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nv_value *
|
||||
nvc0_pc_find_immediate(struct nv_ref *ref)
|
||||
{
|
||||
struct nv_value *src = nvc0_pc_find_constant(ref);
|
||||
|
||||
return (src && (src->reg.file == NV_FILE_IMM || is_gpr63(src))) ? src : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
nv_pc_free_refs(struct nv_pc *pc)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < pc->num_refs; i += 64)
|
||||
FREE(pc->refs[i]);
|
||||
FREE(pc->refs);
|
||||
}
|
||||
|
||||
static const char *
|
||||
edge_name(ubyte type)
|
||||
{
|
||||
switch (type) {
|
||||
case CFG_EDGE_FORWARD: return "forward";
|
||||
case CFG_EDGE_BACK: return "back";
|
||||
case CFG_EDGE_LOOP_ENTER: return "loop";
|
||||
case CFG_EDGE_LOOP_LEAVE: return "break";
|
||||
case CFG_EDGE_FAKE: return "fake";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_pc_pass_in_order(struct nv_basic_block *root, nv_pc_pass_func f,
|
||||
void *priv)
|
||||
{
|
||||
struct nv_basic_block *bb[64], *bbb[16], *b;
|
||||
int j, p, pp;
|
||||
|
||||
bb[0] = root;
|
||||
p = 1;
|
||||
pp = 0;
|
||||
|
||||
while (p > 0) {
|
||||
b = bb[--p];
|
||||
b->priv = 0;
|
||||
|
||||
for (j = 1; j >= 0; --j) {
|
||||
if (!b->out[j])
|
||||
continue;
|
||||
|
||||
switch (b->out_kind[j]) {
|
||||
case CFG_EDGE_BACK:
|
||||
continue;
|
||||
case CFG_EDGE_FORWARD:
|
||||
case CFG_EDGE_FAKE:
|
||||
if (++b->out[j]->priv == b->out[j]->num_in)
|
||||
bb[p++] = b->out[j];
|
||||
break;
|
||||
case CFG_EDGE_LOOP_ENTER:
|
||||
bb[p++] = b->out[j];
|
||||
break;
|
||||
case CFG_EDGE_LOOP_LEAVE:
|
||||
if (!b->out[j]->priv) {
|
||||
bbb[pp++] = b->out[j];
|
||||
b->out[j]->priv = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
f(priv, b);
|
||||
|
||||
if (!p) {
|
||||
p = pp;
|
||||
for (; pp > 0; --pp)
|
||||
bb[pp - 1] = bbb[pp - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nv_do_print_function(void *priv, struct nv_basic_block *b)
|
||||
{
|
||||
struct nv_instruction *i;
|
||||
|
||||
debug_printf("=== BB %i ", b->id);
|
||||
if (b->out[0])
|
||||
debug_printf("[%s -> %i] ", edge_name(b->out_kind[0]), b->out[0]->id);
|
||||
if (b->out[1])
|
||||
debug_printf("[%s -> %i] ", edge_name(b->out_kind[1]), b->out[1]->id);
|
||||
debug_printf("===\n");
|
||||
|
||||
i = b->phi;
|
||||
if (!i)
|
||||
i = b->entry;
|
||||
for (; i; i = i->next)
|
||||
nvc0_print_instruction(i);
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_print_function(struct nv_basic_block *root)
|
||||
{
|
||||
if (root->subroutine)
|
||||
debug_printf("SUBROUTINE %i\n", root->subroutine);
|
||||
else
|
||||
debug_printf("MAIN\n");
|
||||
|
||||
nvc0_pc_pass_in_order(root, nv_do_print_function, root);
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_print_program(struct nv_pc *pc)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < pc->num_subroutines + 1; ++i)
|
||||
if (pc->root[i])
|
||||
nvc0_print_function(pc->root[i]);
|
||||
}
|
||||
|
||||
#if NV50_DEBUG & NV50_DEBUG_PROG_CFLOW
|
||||
static void
|
||||
nv_do_print_cfgraph(struct nv_pc *pc, FILE *f, struct nv_basic_block *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
b->pass_seq = pc->pass_seq;
|
||||
|
||||
fprintf(f, "\t%i [shape=box]\n", b->id);
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (!b->out[i])
|
||||
continue;
|
||||
switch (b->out_kind[i]) {
|
||||
case CFG_EDGE_FORWARD:
|
||||
fprintf(f, "\t%i -> %i;\n", b->id, b->out[i]->id);
|
||||
break;
|
||||
case CFG_EDGE_LOOP_ENTER:
|
||||
fprintf(f, "\t%i -> %i [color=green];\n", b->id, b->out[i]->id);
|
||||
break;
|
||||
case CFG_EDGE_LOOP_LEAVE:
|
||||
fprintf(f, "\t%i -> %i [color=red];\n", b->id, b->out[i]->id);
|
||||
break;
|
||||
case CFG_EDGE_BACK:
|
||||
fprintf(f, "\t%i -> %i;\n", b->id, b->out[i]->id);
|
||||
continue;
|
||||
case CFG_EDGE_FAKE:
|
||||
fprintf(f, "\t%i -> %i [style=dotted];\n", b->id, b->out[i]->id);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
if (b->out[i]->pass_seq < pc->pass_seq)
|
||||
nv_do_print_cfgraph(pc, f, b->out[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the control flow graph of subroutine @subr (0 == MAIN) to a file. */
|
||||
static void
|
||||
nv_print_cfgraph(struct nv_pc *pc, const char *filepath, int subr)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filepath, "a");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
fprintf(f, "digraph G {\n");
|
||||
|
||||
++pc->pass_seq;
|
||||
|
||||
nv_do_print_cfgraph(pc, f, pc->root[subr]);
|
||||
|
||||
fprintf(f, "}\n");
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
static INLINE void
|
||||
nvc0_pc_print_binary(struct nv_pc *pc)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
NV50_DBGMSG(SHADER, "nvc0_pc_print_binary(%u ops)\n", pc->emit_size / 8);
|
||||
|
||||
for (i = 0; i < pc->emit_size / 4; i += 2) {
|
||||
debug_printf("0x%08x ", pc->emit[i + 0]);
|
||||
debug_printf("0x%08x ", pc->emit[i + 1]);
|
||||
if ((i % 16) == 15)
|
||||
debug_printf("\n");
|
||||
}
|
||||
debug_printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
nvc0_emit_program(struct nv_pc *pc)
|
||||
{
|
||||
uint32_t *code = pc->emit;
|
||||
int n;
|
||||
|
||||
NV50_DBGMSG(SHADER, "emitting program: size = %u\n", pc->emit_size);
|
||||
|
||||
pc->emit_pos = 0;
|
||||
for (n = 0; n < pc->num_blocks; ++n) {
|
||||
struct nv_instruction *i;
|
||||
struct nv_basic_block *b = pc->bb_list[n];
|
||||
|
||||
for (i = b->entry; i; i = i->next) {
|
||||
nvc0_emit_instruction(pc, i);
|
||||
pc->emit += 2;
|
||||
pc->emit_pos += 8;
|
||||
}
|
||||
}
|
||||
assert(pc->emit == &code[pc->emit_size / 4]);
|
||||
|
||||
pc->emit[0] = 0x00001de7;
|
||||
pc->emit[1] = 0x80000000;
|
||||
pc->emit_size += 8;
|
||||
|
||||
pc->emit = code;
|
||||
|
||||
#if NV50_DEBUG & NV50_DEBUG_SHADER
|
||||
nvc0_pc_print_binary(pc);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nvc0_generate_code(struct nvc0_translation_info *ti)
|
||||
{
|
||||
struct nv_pc *pc;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
pc = CALLOC_STRUCT(nv_pc);
|
||||
if (!pc)
|
||||
return 1;
|
||||
|
||||
pc->is_fragprog = ti->prog->type == PIPE_SHADER_FRAGMENT;
|
||||
|
||||
pc->root = CALLOC(ti->num_subrs + 1, sizeof(pc->root[0]));
|
||||
if (!pc->root) {
|
||||
FREE(pc);
|
||||
return 1;
|
||||
}
|
||||
pc->num_subroutines = ti->num_subrs;
|
||||
|
||||
ret = nvc0_tgsi_to_nc(pc, ti);
|
||||
if (ret)
|
||||
goto out;
|
||||
#if NV50_DEBUG & NV50_DEBUG_PROG_IR
|
||||
nvc0_print_program(pc);
|
||||
#endif
|
||||
|
||||
pc->opt_reload_elim = ti->require_stores ? FALSE : TRUE;
|
||||
|
||||
/* optimization */
|
||||
ret = nvc0_pc_exec_pass0(pc);
|
||||
if (ret)
|
||||
goto out;
|
||||
#if NV50_DEBUG & NV50_DEBUG_PROG_IR
|
||||
nvc0_print_program(pc);
|
||||
#endif
|
||||
|
||||
/* register allocation */
|
||||
ret = nvc0_pc_exec_pass1(pc);
|
||||
if (ret)
|
||||
goto out;
|
||||
#if NV50_DEBUG & NV50_DEBUG_PROG_CFLOW
|
||||
nvc0_print_program(pc);
|
||||
nv_print_cfgraph(pc, "nvc0_shader_cfgraph.dot", 0);
|
||||
#endif
|
||||
|
||||
/* prepare for emission */
|
||||
ret = nvc0_pc_exec_pass2(pc);
|
||||
if (ret)
|
||||
goto out;
|
||||
assert(!(pc->emit_size % 8));
|
||||
|
||||
pc->emit = CALLOC(pc->emit_size / 4 + 2, 4);
|
||||
if (!pc->emit) {
|
||||
ret = 3;
|
||||
goto out;
|
||||
}
|
||||
ret = nvc0_emit_program(pc);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ti->prog->code = pc->emit;
|
||||
ti->prog->code_base = 0;
|
||||
ti->prog->code_size = pc->emit_size;
|
||||
ti->prog->parm_size = 0;
|
||||
|
||||
ti->prog->max_gpr = MAX2(4, pc->max_reg[NV_FILE_GPR] + 1);
|
||||
|
||||
ti->prog->relocs = pc->reloc_entries;
|
||||
ti->prog->num_relocs = pc->num_relocs;
|
||||
|
||||
NV50_DBGMSG(SHADER, "SHADER TRANSLATION - %s\n", ret ? "failed" : "success");
|
||||
|
||||
out:
|
||||
nv_pc_free_refs(pc);
|
||||
|
||||
for (i = 0; i < pc->num_blocks; ++i)
|
||||
FREE(pc->bb_list[i]);
|
||||
if (pc->root)
|
||||
FREE(pc->root);
|
||||
if (ret) {
|
||||
/* on success, these will be referenced by struct nvc0_program */
|
||||
if (pc->emit)
|
||||
FREE(pc->emit);
|
||||
if (pc->immd_buf)
|
||||
FREE(pc->immd_buf);
|
||||
if (pc->reloc_entries)
|
||||
FREE(pc->reloc_entries);
|
||||
}
|
||||
FREE(pc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
nvbb_insert_phi(struct nv_basic_block *b, struct nv_instruction *i)
|
||||
{
|
||||
if (!b->phi) {
|
||||
i->prev = NULL;
|
||||
b->phi = i;
|
||||
i->next = b->entry;
|
||||
if (b->entry) {
|
||||
assert(!b->entry->prev && b->exit);
|
||||
b->entry->prev = i;
|
||||
} else {
|
||||
b->entry = i;
|
||||
b->exit = i;
|
||||
}
|
||||
} else {
|
||||
assert(b->entry);
|
||||
if (b->entry->opcode == NV_OP_PHI) { /* insert after entry */
|
||||
assert(b->entry == b->exit);
|
||||
b->entry->next = i;
|
||||
i->prev = b->entry;
|
||||
b->entry = i;
|
||||
b->exit = i;
|
||||
} else { /* insert before entry */
|
||||
assert(b->entry->prev && b->exit);
|
||||
i->next = b->entry;
|
||||
i->prev = b->entry->prev;
|
||||
b->entry->prev = i;
|
||||
i->prev->next = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_insn_append(struct nv_basic_block *b, struct nv_instruction *i)
|
||||
{
|
||||
if (i->opcode == NV_OP_PHI) {
|
||||
nvbb_insert_phi(b, i);
|
||||
} else {
|
||||
i->prev = b->exit;
|
||||
if (b->exit)
|
||||
b->exit->next = i;
|
||||
b->exit = i;
|
||||
if (!b->entry)
|
||||
b->entry = i;
|
||||
else
|
||||
if (i->prev && i->prev->opcode == NV_OP_PHI)
|
||||
b->entry = i;
|
||||
}
|
||||
|
||||
i->bb = b;
|
||||
b->num_instructions++;
|
||||
|
||||
if (i->prev && i->prev->terminator)
|
||||
nvc0_insns_permute(i->prev, i);
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_insn_insert_after(struct nv_instruction *at, struct nv_instruction *ni)
|
||||
{
|
||||
if (!at->next) {
|
||||
nvc0_insn_append(at->bb, ni);
|
||||
return;
|
||||
}
|
||||
ni->next = at->next;
|
||||
ni->prev = at;
|
||||
ni->next->prev = ni;
|
||||
ni->prev->next = ni;
|
||||
ni->bb = at->bb;
|
||||
ni->bb->num_instructions++;
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_insn_insert_before(struct nv_instruction *at, struct nv_instruction *ni)
|
||||
{
|
||||
nvc0_insn_insert_after(at, ni);
|
||||
nvc0_insns_permute(at, ni);
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_insn_delete(struct nv_instruction *nvi)
|
||||
{
|
||||
struct nv_basic_block *b = nvi->bb;
|
||||
int s;
|
||||
|
||||
/* debug_printf("REM: "); nv_print_instruction(nvi); */
|
||||
|
||||
for (s = 0; s < 6 && nvi->src[s]; ++s)
|
||||
nv_reference(NULL, nvi, s, NULL);
|
||||
|
||||
if (nvi->next)
|
||||
nvi->next->prev = nvi->prev;
|
||||
else {
|
||||
assert(nvi == b->exit);
|
||||
b->exit = nvi->prev;
|
||||
}
|
||||
|
||||
if (nvi->prev)
|
||||
nvi->prev->next = nvi->next;
|
||||
|
||||
if (nvi == b->entry) {
|
||||
/* PHIs don't get hooked to b->entry */
|
||||
b->entry = nvi->next;
|
||||
assert(!nvi->prev || nvi->prev->opcode == NV_OP_PHI);
|
||||
}
|
||||
|
||||
if (nvi == b->phi) {
|
||||
if (nvi->opcode != NV_OP_PHI)
|
||||
NV50_DBGMSG(PROG_IR, "NOTE: b->phi points to non-PHI instruction\n");
|
||||
|
||||
assert(!nvi->prev);
|
||||
if (!nvi->next || nvi->next->opcode != NV_OP_PHI)
|
||||
b->phi = NULL;
|
||||
else
|
||||
b->phi = nvi->next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_insns_permute(struct nv_instruction *i1, struct nv_instruction *i2)
|
||||
{
|
||||
struct nv_basic_block *b = i1->bb;
|
||||
|
||||
assert(i1->opcode != NV_OP_PHI &&
|
||||
i2->opcode != NV_OP_PHI);
|
||||
assert(i1->next == i2);
|
||||
|
||||
if (b->exit == i2)
|
||||
b->exit = i1;
|
||||
|
||||
if (b->entry == i1)
|
||||
b->entry = i2;
|
||||
|
||||
i2->prev = i1->prev;
|
||||
i1->next = i2->next;
|
||||
i2->next = i1;
|
||||
i1->prev = i2;
|
||||
|
||||
if (i2->prev)
|
||||
i2->prev->next = i2;
|
||||
if (i1->next)
|
||||
i1->next->prev = i1;
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_bblock_attach(struct nv_basic_block *parent,
|
||||
struct nv_basic_block *b, ubyte edge_kind)
|
||||
{
|
||||
assert(b->num_in < 8);
|
||||
|
||||
if (parent->out[0]) {
|
||||
assert(!parent->out[1]);
|
||||
parent->out[1] = b;
|
||||
parent->out_kind[1] = edge_kind;
|
||||
} else {
|
||||
parent->out[0] = b;
|
||||
parent->out_kind[0] = edge_kind;
|
||||
}
|
||||
|
||||
b->in[b->num_in] = parent;
|
||||
b->in_kind[b->num_in++] = edge_kind;
|
||||
}
|
||||
|
||||
/* NOTE: all BRKs are treated as conditional, so there are 2 outgoing BBs */
|
||||
|
||||
boolean
|
||||
nvc0_bblock_dominated_by(struct nv_basic_block *b, struct nv_basic_block *d)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (b == d)
|
||||
return TRUE;
|
||||
|
||||
for (j = 0; j < b->num_in; ++j)
|
||||
if ((b->in_kind[j] != CFG_EDGE_BACK) &&
|
||||
!nvc0_bblock_dominated_by(b->in[j], d))
|
||||
return FALSE;
|
||||
|
||||
return j ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/* check if @bf (future) can be reached from @bp (past), stop at @bt */
|
||||
boolean
|
||||
nvc0_bblock_reachable_by(struct nv_basic_block *bf, struct nv_basic_block *bp,
|
||||
struct nv_basic_block *bt)
|
||||
{
|
||||
struct nv_basic_block *q[NV_PC_MAX_BASIC_BLOCKS], *b;
|
||||
int i, p, n;
|
||||
|
||||
p = 0;
|
||||
n = 1;
|
||||
q[0] = bp;
|
||||
|
||||
while (p < n) {
|
||||
b = q[p++];
|
||||
|
||||
if (b == bf)
|
||||
break;
|
||||
if (b == bt)
|
||||
continue;
|
||||
assert(n <= (1024 - 2));
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (b->out[i] && !IS_WALL_EDGE(b->out_kind[i]) && !b->out[i]->priv) {
|
||||
q[n] = b->out[i];
|
||||
q[n++]->priv = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (--n; n >= 0; --n)
|
||||
q[n]->priv = 0;
|
||||
|
||||
return (b == bf);
|
||||
}
|
||||
|
||||
static struct nv_basic_block *
|
||||
nvbb_find_dom_frontier(struct nv_basic_block *b, struct nv_basic_block *df)
|
||||
{
|
||||
struct nv_basic_block *out;
|
||||
int i;
|
||||
|
||||
if (!nvc0_bblock_dominated_by(df, b)) {
|
||||
for (i = 0; i < df->num_in; ++i) {
|
||||
if (df->in_kind[i] == CFG_EDGE_BACK)
|
||||
continue;
|
||||
if (nvc0_bblock_dominated_by(df->in[i], b))
|
||||
return df;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 2 && df->out[i]; ++i) {
|
||||
if (df->out_kind[i] == CFG_EDGE_BACK)
|
||||
continue;
|
||||
if ((out = nvbb_find_dom_frontier(b, df->out[i])))
|
||||
return out;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nv_basic_block *
|
||||
nvc0_bblock_dom_frontier(struct nv_basic_block *b)
|
||||
{
|
||||
struct nv_basic_block *df;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2 && b->out[i]; ++i)
|
||||
if ((df = nvbb_find_dom_frontier(b, b->out[i])))
|
||||
return df;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,637 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 Christoph Bumiller
|
||||
*
|
||||
* 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 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 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 __NVC0_COMPILER_H__
|
||||
#define __NVC0_COMPILER_H__
|
||||
|
||||
#include "nv50/nv50_debug.h"
|
||||
|
||||
#include "pipe/p_defines.h"
|
||||
#include "util/u_inlines.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "util/u_double_list.h"
|
||||
|
||||
/* pseudo opcodes */
|
||||
#define NV_OP_UNDEF 0
|
||||
#define NV_OP_BIND 1
|
||||
#define NV_OP_MERGE 2
|
||||
#define NV_OP_PHI 3
|
||||
#define NV_OP_SELECT 4
|
||||
#define NV_OP_NOP 5
|
||||
|
||||
/**
|
||||
* BIND forces source operand i into the same register as destination operand i,
|
||||
* and the operands will be assigned consecutive registers (needed for TEX).
|
||||
* Beware conflicts !
|
||||
* SELECT forces its multiple source operands and its destination operand into
|
||||
* one and the same register.
|
||||
*/
|
||||
|
||||
/* base opcodes */
|
||||
#define NV_OP_LD 6
|
||||
#define NV_OP_ST 7
|
||||
#define NV_OP_MOV 8
|
||||
#define NV_OP_AND 9
|
||||
#define NV_OP_OR 10
|
||||
#define NV_OP_XOR 11
|
||||
#define NV_OP_SHL 12
|
||||
#define NV_OP_SHR 13
|
||||
#define NV_OP_NOT 14
|
||||
#define NV_OP_SET 15
|
||||
#define NV_OP_ADD 16
|
||||
#define NV_OP_SUB 17
|
||||
#define NV_OP_MUL 18
|
||||
#define NV_OP_MAD 19
|
||||
#define NV_OP_ABS 20
|
||||
#define NV_OP_NEG 21
|
||||
#define NV_OP_MAX 22
|
||||
#define NV_OP_MIN 23
|
||||
#define NV_OP_CVT 24
|
||||
#define NV_OP_CEIL 25
|
||||
#define NV_OP_FLOOR 26
|
||||
#define NV_OP_TRUNC 27
|
||||
#define NV_OP_SAD 28
|
||||
|
||||
/* shader opcodes */
|
||||
#define NV_OP_VFETCH 29
|
||||
#define NV_OP_PFETCH 30
|
||||
#define NV_OP_EXPORT 31
|
||||
#define NV_OP_LINTERP 32
|
||||
#define NV_OP_PINTERP 33
|
||||
#define NV_OP_EMIT 34
|
||||
#define NV_OP_RESTART 35
|
||||
#define NV_OP_TEX 36
|
||||
#define NV_OP_TXB 37
|
||||
#define NV_OP_TXL 38
|
||||
#define NV_OP_TXF 39
|
||||
#define NV_OP_TXQ 40
|
||||
#define NV_OP_QUADOP 41
|
||||
#define NV_OP_DFDX 42
|
||||
#define NV_OP_DFDY 43
|
||||
#define NV_OP_KIL 44
|
||||
|
||||
/* control flow opcodes */
|
||||
#define NV_OP_BRA 45
|
||||
#define NV_OP_CALL 46
|
||||
#define NV_OP_RET 47
|
||||
#define NV_OP_EXIT 48
|
||||
#define NV_OP_BREAK 49
|
||||
#define NV_OP_BREAKADDR 50
|
||||
#define NV_OP_JOINAT 51
|
||||
#define NV_OP_JOIN 52
|
||||
|
||||
/* typed opcodes */
|
||||
#define NV_OP_ADD_F32 NV_OP_ADD
|
||||
#define NV_OP_ADD_B32 53
|
||||
#define NV_OP_MUL_F32 NV_OP_MUL
|
||||
#define NV_OP_MUL_B32 54
|
||||
#define NV_OP_ABS_F32 NV_OP_ABS
|
||||
#define NV_OP_ABS_S32 55
|
||||
#define NV_OP_NEG_F32 NV_OP_NEG
|
||||
#define NV_OP_NEG_S32 56
|
||||
#define NV_OP_MAX_F32 NV_OP_MAX
|
||||
#define NV_OP_MAX_S32 57
|
||||
#define NV_OP_MAX_U32 58
|
||||
#define NV_OP_MIN_F32 NV_OP_MIN
|
||||
#define NV_OP_MIN_S32 59
|
||||
#define NV_OP_MIN_U32 60
|
||||
#define NV_OP_SET_F32 61
|
||||
#define NV_OP_SET_S32 62
|
||||
#define NV_OP_SET_U32 63
|
||||
#define NV_OP_SAR 64
|
||||
#define NV_OP_RCP 65
|
||||
#define NV_OP_RSQ 66
|
||||
#define NV_OP_LG2 67
|
||||
#define NV_OP_SIN 68
|
||||
#define NV_OP_COS 69
|
||||
#define NV_OP_EX2 70
|
||||
#define NV_OP_PRESIN 71
|
||||
#define NV_OP_PREEX2 72
|
||||
#define NV_OP_SAT 73
|
||||
|
||||
/* newly added opcodes */
|
||||
#define NV_OP_SET_F32_AND 74
|
||||
#define NV_OP_SET_F32_OR 75
|
||||
#define NV_OP_SET_F32_XOR 76
|
||||
#define NV_OP_SELP 77
|
||||
#define NV_OP_SLCT 78
|
||||
#define NV_OP_SLCT_F32 NV_OP_SLCT
|
||||
#define NV_OP_SLCT_S32 79
|
||||
#define NV_OP_SLCT_U32 80
|
||||
#define NV_OP_SUB_F32 NV_OP_SUB
|
||||
#define NV_OP_SUB_S32 81
|
||||
#define NV_OP_MAD_F32 NV_OP_MAD
|
||||
#define NV_OP_FSET_F32 82
|
||||
#define NV_OP_TXG 83
|
||||
|
||||
#define NV_OP_COUNT 84
|
||||
|
||||
/* nv50 files omitted */
|
||||
#define NV_FILE_GPR 0
|
||||
#define NV_FILE_COND 1
|
||||
#define NV_FILE_PRED 2
|
||||
#define NV_FILE_IMM 16
|
||||
#define NV_FILE_MEM_S 32
|
||||
#define NV_FILE_MEM_V 34
|
||||
#define NV_FILE_MEM_A 35
|
||||
#define NV_FILE_MEM_L 48
|
||||
#define NV_FILE_MEM_G 64
|
||||
#define NV_FILE_MEM_C(i) (80 + i)
|
||||
|
||||
#define NV_IS_MEMORY_FILE(f) ((f) >= NV_FILE_MEM_S)
|
||||
|
||||
#define NV_MOD_NEG 1
|
||||
#define NV_MOD_ABS 2
|
||||
#define NV_MOD_NOT 4
|
||||
#define NV_MOD_SAT 8
|
||||
|
||||
#define NV_TYPE_U8 0x00
|
||||
#define NV_TYPE_S8 0x01
|
||||
#define NV_TYPE_U16 0x02
|
||||
#define NV_TYPE_S16 0x03
|
||||
#define NV_TYPE_U32 0x04
|
||||
#define NV_TYPE_S32 0x05
|
||||
#define NV_TYPE_P32 0x07
|
||||
#define NV_TYPE_F32 0x09
|
||||
#define NV_TYPE_F64 0x0b
|
||||
#define NV_TYPE_VEC(x, n) (NV_TYPE_##x | (n << 4))
|
||||
#define NV_TYPE_ANY 0xff
|
||||
|
||||
#define NV_TYPE_ISINT(t) ((t) < 7)
|
||||
#define NV_TYPE_ISSGD(t) ((t) & 1)
|
||||
|
||||
#define NV_CC_FL 0x0
|
||||
#define NV_CC_LT 0x1
|
||||
#define NV_CC_EQ 0x2
|
||||
#define NV_CC_LE 0x3
|
||||
#define NV_CC_GT 0x4
|
||||
#define NV_CC_NE 0x5
|
||||
#define NV_CC_GE 0x6
|
||||
#define NV_CC_U 0x8
|
||||
#define NV_CC_TR 0xf
|
||||
#define NV_CC_O 0x10
|
||||
#define NV_CC_C 0x11
|
||||
#define NV_CC_A 0x12
|
||||
#define NV_CC_S 0x13
|
||||
#define NV_CC_INVERSE(cc) ((cc) ^ 0x7)
|
||||
/* for 1 bit predicates: */
|
||||
#define NV_CC_P 0
|
||||
#define NV_CC_NOT_P 1
|
||||
|
||||
uint8_t nvc0_ir_reverse_cc(uint8_t cc);
|
||||
|
||||
#define NV_PC_MAX_INSTRUCTIONS 2048
|
||||
#define NV_PC_MAX_VALUES (NV_PC_MAX_INSTRUCTIONS * 4)
|
||||
|
||||
#define NV_PC_MAX_BASIC_BLOCKS 1024
|
||||
|
||||
struct nv_op_info {
|
||||
uint base; /* e.g. ADD_S32 -> ADD */
|
||||
char name[12];
|
||||
uint8_t type;
|
||||
uint16_t mods;
|
||||
unsigned flow : 1;
|
||||
unsigned commutative : 1;
|
||||
unsigned vector : 1;
|
||||
unsigned predicate : 1;
|
||||
unsigned pseudo : 1;
|
||||
unsigned immediate : 3;
|
||||
unsigned memory : 3;
|
||||
};
|
||||
|
||||
extern struct nv_op_info nvc0_op_info_table[];
|
||||
|
||||
#define NV_BASEOP(op) (nvc0_op_info_table[op].base)
|
||||
#define NV_OPTYPE(op) (nvc0_op_info_table[op].type)
|
||||
|
||||
static INLINE boolean
|
||||
nv_is_texture_op(uint opcode)
|
||||
{
|
||||
return (opcode >= NV_OP_TEX && opcode <= NV_OP_TXQ);
|
||||
}
|
||||
|
||||
static INLINE boolean
|
||||
nv_is_vector_op(uint opcode)
|
||||
{
|
||||
return nvc0_op_info_table[opcode].vector ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static INLINE boolean
|
||||
nv_op_commutative(uint opcode)
|
||||
{
|
||||
return nvc0_op_info_table[opcode].commutative ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static INLINE uint8_t
|
||||
nv_op_supported_src_mods(uint opcode, int s)
|
||||
{
|
||||
return (nvc0_op_info_table[opcode].mods >> (s * 4)) & 0xf;
|
||||
}
|
||||
|
||||
static INLINE uint
|
||||
nv_type_order(ubyte type)
|
||||
{
|
||||
switch (type & 0xf) {
|
||||
case NV_TYPE_U8:
|
||||
case NV_TYPE_S8:
|
||||
return 0;
|
||||
case NV_TYPE_U16:
|
||||
case NV_TYPE_S16:
|
||||
return 1;
|
||||
case NV_TYPE_U32:
|
||||
case NV_TYPE_F32:
|
||||
case NV_TYPE_S32:
|
||||
case NV_TYPE_P32:
|
||||
return 2;
|
||||
case NV_TYPE_F64:
|
||||
return 3;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE uint
|
||||
nv_type_sizeof(ubyte type)
|
||||
{
|
||||
if (type & 0xf0)
|
||||
return (1 << nv_type_order(type)) * (type >> 4);
|
||||
return 1 << nv_type_order(type);
|
||||
}
|
||||
|
||||
static INLINE uint
|
||||
nv_type_sizeof_base(ubyte type)
|
||||
{
|
||||
return 1 << nv_type_order(type);
|
||||
}
|
||||
|
||||
struct nv_reg {
|
||||
uint32_t address; /* for memory locations */
|
||||
int id; /* for registers */
|
||||
ubyte file;
|
||||
ubyte size;
|
||||
union {
|
||||
int32_t s32;
|
||||
int64_t s64;
|
||||
uint64_t u64;
|
||||
uint32_t u32; /* expected to be 0 for $r63 */
|
||||
float f32;
|
||||
double f64;
|
||||
} imm;
|
||||
};
|
||||
|
||||
struct nv_range {
|
||||
struct nv_range *next;
|
||||
int bgn;
|
||||
int end;
|
||||
};
|
||||
|
||||
struct nv_ref;
|
||||
|
||||
struct nv_value {
|
||||
struct nv_reg reg;
|
||||
struct nv_instruction *insn;
|
||||
struct nv_value *join;
|
||||
struct nv_ref *last_use;
|
||||
int n;
|
||||
struct nv_range *livei;
|
||||
int refc;
|
||||
struct nv_value *next;
|
||||
struct nv_value *prev;
|
||||
};
|
||||
|
||||
struct nv_ref {
|
||||
struct nv_value *value;
|
||||
struct nv_instruction *insn;
|
||||
struct list_head list; /* connects uses of the same value */
|
||||
uint8_t mod;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define NV_REF_FLAG_REGALLOC_PRIV (1 << 0)
|
||||
|
||||
struct nv_basic_block;
|
||||
|
||||
struct nv_instruction {
|
||||
struct nv_instruction *next;
|
||||
struct nv_instruction *prev;
|
||||
uint opcode;
|
||||
uint serial;
|
||||
|
||||
struct nv_value *def[5];
|
||||
struct nv_ref *src[6];
|
||||
|
||||
int8_t predicate; /* index of predicate src */
|
||||
int8_t indirect; /* index of pointer src */
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint8_t t; /* TIC binding */
|
||||
uint8_t s; /* TSC binding */
|
||||
} tex;
|
||||
struct {
|
||||
uint8_t d; /* output type */
|
||||
uint8_t s; /* input type */
|
||||
} cvt;
|
||||
} ext;
|
||||
|
||||
struct nv_basic_block *bb;
|
||||
struct nv_basic_block *target; /* target block of control flow insn */
|
||||
|
||||
unsigned cc : 5; /* condition code */
|
||||
unsigned fixed : 1; /* don't optimize away (prematurely) */
|
||||
unsigned terminator : 1;
|
||||
unsigned join : 1;
|
||||
unsigned set_cond : 4; /* 2nd byte */
|
||||
unsigned saturate : 1;
|
||||
unsigned centroid : 1;
|
||||
unsigned flat : 1;
|
||||
unsigned patch : 1;
|
||||
unsigned lanes : 4; /* 3rd byte */
|
||||
unsigned tex_dim : 2;
|
||||
unsigned tex_array : 1;
|
||||
unsigned tex_cube : 1;
|
||||
unsigned tex_shadow : 1; /* 4th byte */
|
||||
unsigned tex_live : 1;
|
||||
unsigned tex_mask : 4;
|
||||
|
||||
uint8_t quadop;
|
||||
};
|
||||
|
||||
static INLINE int
|
||||
nvi_vector_size(struct nv_instruction *nvi)
|
||||
{
|
||||
int i;
|
||||
assert(nvi);
|
||||
for (i = 0; i < 5 && nvi->def[i]; ++i);
|
||||
return i;
|
||||
}
|
||||
|
||||
#define CFG_EDGE_FORWARD 0
|
||||
#define CFG_EDGE_BACK 1
|
||||
#define CFG_EDGE_LOOP_ENTER 2
|
||||
#define CFG_EDGE_LOOP_LEAVE 4
|
||||
#define CFG_EDGE_FAKE 8
|
||||
|
||||
/* 'WALL' edge means where reachability check doesn't follow */
|
||||
/* 'LOOP' edge means just having to do with loops */
|
||||
#define IS_LOOP_EDGE(k) ((k) & 7)
|
||||
#define IS_WALL_EDGE(k) ((k) & 9)
|
||||
|
||||
struct nv_basic_block {
|
||||
struct nv_instruction *entry; /* first non-phi instruction */
|
||||
struct nv_instruction *exit;
|
||||
struct nv_instruction *phi; /* very first instruction */
|
||||
int num_instructions;
|
||||
|
||||
struct nv_basic_block *out[2]; /* no indirect branches -> 2 */
|
||||
struct nv_basic_block *in[8]; /* hope that suffices */
|
||||
uint num_in;
|
||||
ubyte out_kind[2];
|
||||
ubyte in_kind[8];
|
||||
|
||||
int id;
|
||||
int subroutine;
|
||||
uint priv; /* reset to 0 after you're done */
|
||||
uint pass_seq;
|
||||
|
||||
uint32_t emit_pos; /* position, size in emitted code (in bytes) */
|
||||
uint32_t emit_size;
|
||||
|
||||
uint32_t live_set[NV_PC_MAX_VALUES / 32];
|
||||
};
|
||||
|
||||
struct nvc0_translation_info;
|
||||
|
||||
struct nv_pc {
|
||||
struct nv_basic_block **root;
|
||||
struct nv_basic_block *current_block;
|
||||
struct nv_basic_block *parent_block;
|
||||
|
||||
int loop_nesting_bound;
|
||||
uint pass_seq;
|
||||
|
||||
struct nv_value values[NV_PC_MAX_VALUES];
|
||||
struct nv_instruction instructions[NV_PC_MAX_INSTRUCTIONS];
|
||||
struct nv_ref **refs;
|
||||
struct nv_basic_block *bb_list[NV_PC_MAX_BASIC_BLOCKS];
|
||||
int num_values;
|
||||
int num_instructions;
|
||||
int num_refs;
|
||||
int num_blocks;
|
||||
int num_subroutines;
|
||||
|
||||
int max_reg[4];
|
||||
|
||||
uint32_t *immd_buf; /* populated on emit */
|
||||
unsigned immd_count;
|
||||
|
||||
uint32_t *emit;
|
||||
uint32_t emit_size;
|
||||
uint32_t emit_pos;
|
||||
|
||||
void *reloc_entries;
|
||||
unsigned num_relocs;
|
||||
|
||||
/* optimization enables */
|
||||
boolean opt_reload_elim;
|
||||
boolean is_fragprog;
|
||||
};
|
||||
|
||||
void nvc0_insn_append(struct nv_basic_block *, struct nv_instruction *);
|
||||
void nvc0_insn_insert_before(struct nv_instruction *, struct nv_instruction *);
|
||||
void nvc0_insn_insert_after(struct nv_instruction *, struct nv_instruction *);
|
||||
|
||||
static INLINE struct nv_instruction *
|
||||
nv_alloc_instruction(struct nv_pc *pc, uint opcode)
|
||||
{
|
||||
struct nv_instruction *insn;
|
||||
|
||||
insn = &pc->instructions[pc->num_instructions++];
|
||||
assert(pc->num_instructions < NV_PC_MAX_INSTRUCTIONS);
|
||||
|
||||
insn->opcode = opcode;
|
||||
insn->cc = NV_CC_P;
|
||||
insn->indirect = -1;
|
||||
insn->predicate = -1;
|
||||
|
||||
return insn;
|
||||
}
|
||||
|
||||
static INLINE struct nv_instruction *
|
||||
new_instruction(struct nv_pc *pc, uint opcode)
|
||||
{
|
||||
struct nv_instruction *insn = nv_alloc_instruction(pc, opcode);
|
||||
|
||||
nvc0_insn_append(pc->current_block, insn);
|
||||
return insn;
|
||||
}
|
||||
|
||||
static INLINE struct nv_instruction *
|
||||
new_instruction_at(struct nv_pc *pc, struct nv_instruction *at, uint opcode)
|
||||
{
|
||||
struct nv_instruction *insn = nv_alloc_instruction(pc, opcode);
|
||||
|
||||
nvc0_insn_insert_after(at, insn);
|
||||
return insn;
|
||||
}
|
||||
|
||||
static INLINE struct nv_value *
|
||||
new_value(struct nv_pc *pc, ubyte file, ubyte size)
|
||||
{
|
||||
struct nv_value *value = &pc->values[pc->num_values];
|
||||
|
||||
assert(pc->num_values < NV_PC_MAX_VALUES - 1);
|
||||
|
||||
value->n = pc->num_values++;
|
||||
value->join = value;
|
||||
value->reg.id = -1;
|
||||
value->reg.file = file;
|
||||
value->reg.size = size;
|
||||
return value;
|
||||
}
|
||||
|
||||
static INLINE struct nv_value *
|
||||
new_value_like(struct nv_pc *pc, struct nv_value *like)
|
||||
{
|
||||
return new_value(pc, like->reg.file, like->reg.size);
|
||||
}
|
||||
|
||||
static INLINE struct nv_ref *
|
||||
new_ref(struct nv_pc *pc, struct nv_value *val)
|
||||
{
|
||||
int i;
|
||||
struct nv_ref *ref;
|
||||
|
||||
if ((pc->num_refs % 64) == 0) {
|
||||
const unsigned old_size = pc->num_refs * sizeof(struct nv_ref *);
|
||||
const unsigned new_size = (pc->num_refs + 64) * sizeof(struct nv_ref *);
|
||||
|
||||
pc->refs = REALLOC(pc->refs, old_size, new_size);
|
||||
|
||||
ref = CALLOC(64, sizeof(struct nv_ref));
|
||||
for (i = 0; i < 64; ++i)
|
||||
pc->refs[pc->num_refs + i] = &ref[i];
|
||||
}
|
||||
|
||||
ref = pc->refs[pc->num_refs++];
|
||||
ref->value = val;
|
||||
|
||||
LIST_INITHEAD(&ref->list);
|
||||
|
||||
++val->refc;
|
||||
return ref;
|
||||
}
|
||||
|
||||
static INLINE struct nv_basic_block *
|
||||
new_basic_block(struct nv_pc *pc)
|
||||
{
|
||||
struct nv_basic_block *bb;
|
||||
|
||||
if (pc->num_blocks >= NV_PC_MAX_BASIC_BLOCKS)
|
||||
return NULL;
|
||||
|
||||
bb = CALLOC_STRUCT(nv_basic_block);
|
||||
|
||||
bb->id = pc->num_blocks;
|
||||
pc->bb_list[pc->num_blocks++] = bb;
|
||||
return bb;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
nv_reference(struct nv_pc *pc,
|
||||
struct nv_instruction *nvi, int c, struct nv_value *s)
|
||||
{
|
||||
struct nv_ref **d = &nvi->src[c];
|
||||
assert(c < 6);
|
||||
|
||||
if (*d) {
|
||||
--(*d)->value->refc;
|
||||
LIST_DEL(&(*d)->list);
|
||||
}
|
||||
|
||||
if (s) {
|
||||
if (!*d) {
|
||||
*d = new_ref(pc, s);
|
||||
(*d)->insn = nvi;
|
||||
} else {
|
||||
LIST_DEL(&(*d)->list);
|
||||
(*d)->value = s;
|
||||
++(s->refc);
|
||||
}
|
||||
if (!s->last_use)
|
||||
s->last_use = *d;
|
||||
else
|
||||
LIST_ADDTAIL(&s->last_use->list, &(*d)->list);
|
||||
|
||||
s->last_use = *d;
|
||||
(*d)->insn = nvi;
|
||||
} else {
|
||||
*d = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* nvc0_emit.c */
|
||||
void nvc0_emit_instruction(struct nv_pc *, struct nv_instruction *);
|
||||
|
||||
/* nvc0_print.c */
|
||||
const char *nvc0_opcode_name(uint opcode);
|
||||
void nvc0_print_instruction(struct nv_instruction *);
|
||||
|
||||
/* nvc0_pc.c */
|
||||
void nvc0_print_function(struct nv_basic_block *root);
|
||||
void nvc0_print_program(struct nv_pc *);
|
||||
|
||||
boolean nvc0_insn_can_load(struct nv_instruction *, int s,
|
||||
struct nv_instruction *);
|
||||
boolean nvc0_insn_is_predicateable(struct nv_instruction *);
|
||||
|
||||
int nvc0_insn_refcount(struct nv_instruction *);
|
||||
void nvc0_insn_delete(struct nv_instruction *);
|
||||
void nvc0_insns_permute(struct nv_instruction *prev, struct nv_instruction *);
|
||||
|
||||
void nvc0_bblock_attach(struct nv_basic_block *parent,
|
||||
struct nv_basic_block *child, ubyte edge_kind);
|
||||
boolean nvc0_bblock_dominated_by(struct nv_basic_block *,
|
||||
struct nv_basic_block *);
|
||||
boolean nvc0_bblock_reachable_by(struct nv_basic_block *future,
|
||||
struct nv_basic_block *past,
|
||||
struct nv_basic_block *final);
|
||||
struct nv_basic_block *nvc0_bblock_dom_frontier(struct nv_basic_block *);
|
||||
|
||||
int nvc0_pc_replace_value(struct nv_pc *pc,
|
||||
struct nv_value *old_val,
|
||||
struct nv_value *new_val);
|
||||
|
||||
struct nv_value *nvc0_pc_find_immediate(struct nv_ref *);
|
||||
struct nv_value *nvc0_pc_find_constant(struct nv_ref *);
|
||||
|
||||
typedef void (*nv_pc_pass_func)(void *priv, struct nv_basic_block *b);
|
||||
|
||||
void nvc0_pc_pass_in_order(struct nv_basic_block *, nv_pc_pass_func, void *);
|
||||
|
||||
int nvc0_pc_exec_pass0(struct nv_pc *pc);
|
||||
int nvc0_pc_exec_pass1(struct nv_pc *pc);
|
||||
int nvc0_pc_exec_pass2(struct nv_pc *pc);
|
||||
|
||||
int nvc0_tgsi_to_nc(struct nv_pc *, struct nvc0_translation_info *);
|
||||
|
||||
#endif // NV50_COMPILER_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,381 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 Christoph Bumiller
|
||||
*
|
||||
* 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 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 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 "nvc0_pc.h"
|
||||
|
||||
#define PRINT(args...) debug_printf(args)
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
static const char *norm = "\x1b[00m";
|
||||
static const char *gree = "\x1b[32m";
|
||||
static const char *blue = "\x1b[34m";
|
||||
static const char *cyan = "\x1b[36m";
|
||||
static const char *yllw = "\x1b[33m";
|
||||
static const char *mgta = "\x1b[35m";
|
||||
|
||||
static const char *nv_cond_names[] =
|
||||
{
|
||||
"never", "lt" , "eq" , "le" , "gt" , "ne" , "ge" , "",
|
||||
"never", "ltu", "equ", "leu", "gtu", "neu", "geu", "",
|
||||
"o", "c", "a", "s"
|
||||
};
|
||||
|
||||
static const char *nv_modifier_strings[] =
|
||||
{
|
||||
"",
|
||||
"neg",
|
||||
"abs",
|
||||
"neg abs",
|
||||
"not",
|
||||
"not neg"
|
||||
"not abs",
|
||||
"not neg abs",
|
||||
"sat",
|
||||
"BAD_MOD"
|
||||
};
|
||||
|
||||
const char *
|
||||
nvc0_opcode_name(uint opcode)
|
||||
{
|
||||
return nvc0_op_info_table[MIN2(opcode, NV_OP_COUNT)].name;
|
||||
}
|
||||
|
||||
static INLINE const char *
|
||||
nv_type_name(ubyte type, ubyte size)
|
||||
{
|
||||
switch (type) {
|
||||
case NV_TYPE_U16: return "u16";
|
||||
case NV_TYPE_S16: return "s16";
|
||||
case NV_TYPE_F32: return "f32";
|
||||
case NV_TYPE_U32: return "u32";
|
||||
case NV_TYPE_S32: return "s32";
|
||||
case NV_TYPE_P32: return "p32";
|
||||
case NV_TYPE_F64: return "f64";
|
||||
case NV_TYPE_ANY:
|
||||
{
|
||||
switch (size) {
|
||||
case 1: return "b8";
|
||||
case 2: return "b16";
|
||||
case 4: return "b32";
|
||||
case 8: return "b64";
|
||||
case 12: return "b96";
|
||||
case 16: return "b128";
|
||||
default:
|
||||
return "BAD_SIZE";
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "BAD_TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE const char *
|
||||
nv_cond_name(ubyte cc)
|
||||
{
|
||||
return nv_cond_names[MIN2(cc, 19)];
|
||||
}
|
||||
|
||||
static INLINE const char *
|
||||
nv_modifier_string(ubyte mod)
|
||||
{
|
||||
return nv_modifier_strings[MIN2(mod, 9)];
|
||||
}
|
||||
|
||||
static INLINE int
|
||||
nv_value_id(struct nv_value *value)
|
||||
{
|
||||
if (value->join->reg.id >= 0)
|
||||
return value->join->reg.id;
|
||||
return value->n;
|
||||
}
|
||||
|
||||
static INLINE boolean
|
||||
nv_value_allocated(struct nv_value *value)
|
||||
{
|
||||
return (value->reg.id >= 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
nv_print_address(const char c, int buf, struct nv_value *a, int offset)
|
||||
{
|
||||
const char ac = (a && nv_value_allocated(a)) ? '$' : '%';
|
||||
char sg;
|
||||
|
||||
if (offset < 0) {
|
||||
sg = '-';
|
||||
offset = -offset;
|
||||
} else {
|
||||
sg = '+';
|
||||
}
|
||||
|
||||
if (buf >= 0)
|
||||
PRINT(" %s%c%i[", cyan, c, buf);
|
||||
else
|
||||
PRINT(" %s%c[", cyan, c);
|
||||
if (a)
|
||||
PRINT("%s%ca%i%s%c", mgta, ac, nv_value_id(a), cyan, sg);
|
||||
PRINT("%s0x%x%s]", yllw, offset, cyan);
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
nv_print_value(struct nv_value *value, struct nv_value *indir, ubyte type)
|
||||
{
|
||||
char reg_pfx = nv_value_allocated(value->join) ? '$' : '%';
|
||||
|
||||
if (value->reg.file != NV_FILE_PRED)
|
||||
PRINT(" %s%s", gree, nv_type_name(type, value->reg.size));
|
||||
|
||||
switch (value->reg.file) {
|
||||
case NV_FILE_GPR:
|
||||
PRINT(" %s%cr%i", blue, reg_pfx, nv_value_id(value));
|
||||
if (value->reg.size == 8)
|
||||
PRINT("d");
|
||||
if (value->reg.size == 16)
|
||||
PRINT("q");
|
||||
break;
|
||||
case NV_FILE_PRED:
|
||||
PRINT(" %s%cp%i", mgta, reg_pfx, nv_value_id(value));
|
||||
break;
|
||||
case NV_FILE_COND:
|
||||
PRINT(" %s%cc%i", mgta, reg_pfx, nv_value_id(value));
|
||||
break;
|
||||
case NV_FILE_MEM_L:
|
||||
nv_print_address('l', -1, indir, value->reg.address);
|
||||
break;
|
||||
case NV_FILE_MEM_G:
|
||||
nv_print_address('g', -1, indir, value->reg.address);
|
||||
break;
|
||||
case NV_FILE_MEM_A:
|
||||
nv_print_address('a', -1, indir, value->reg.address);
|
||||
break;
|
||||
case NV_FILE_MEM_V:
|
||||
nv_print_address('v', -1, indir, value->reg.address);
|
||||
break;
|
||||
case NV_FILE_IMM:
|
||||
switch (type) {
|
||||
case NV_TYPE_U16:
|
||||
case NV_TYPE_S16:
|
||||
PRINT(" %s0x%04x", yllw, value->reg.imm.u32);
|
||||
break;
|
||||
case NV_TYPE_F32:
|
||||
PRINT(" %s%f", yllw, value->reg.imm.f32);
|
||||
break;
|
||||
case NV_TYPE_F64:
|
||||
PRINT(" %s%f", yllw, value->reg.imm.f64);
|
||||
break;
|
||||
case NV_TYPE_U32:
|
||||
case NV_TYPE_S32:
|
||||
case NV_TYPE_P32:
|
||||
case NV_TYPE_ANY:
|
||||
PRINT(" %s0x%08x", yllw, value->reg.imm.u32);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (value->reg.file >= NV_FILE_MEM_C(0) &&
|
||||
value->reg.file <= NV_FILE_MEM_C(15))
|
||||
nv_print_address('c', value->reg.file - NV_FILE_MEM_C(0), indir,
|
||||
value->reg.address);
|
||||
else
|
||||
NOUVEAU_ERR(" BAD_FILE[%i]", nv_value_id(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
nv_print_ref(struct nv_ref *ref, struct nv_value *indir, ubyte type)
|
||||
{
|
||||
nv_print_value(ref->value, indir, type);
|
||||
}
|
||||
|
||||
void
|
||||
nvc0_print_instruction(struct nv_instruction *i)
|
||||
{
|
||||
int s;
|
||||
|
||||
PRINT("%i: ", i->serial);
|
||||
|
||||
if (i->predicate >= 0) {
|
||||
PRINT("%s%s", gree, i->cc ? "fl" : "tr");
|
||||
nv_print_ref(i->src[i->predicate], NULL, NV_TYPE_U8);
|
||||
PRINT(" ");
|
||||
}
|
||||
|
||||
PRINT("%s", gree);
|
||||
if (NV_BASEOP(i->opcode) == NV_OP_SET)
|
||||
PRINT("%s %s", nvc0_opcode_name(i->opcode), nv_cond_name(i->set_cond));
|
||||
else
|
||||
if (i->saturate)
|
||||
PRINT("sat %s", nvc0_opcode_name(i->opcode));
|
||||
else
|
||||
PRINT("%s", nvc0_opcode_name(i->opcode));
|
||||
|
||||
if (i->opcode == NV_OP_CVT)
|
||||
nv_print_value(i->def[0], NULL, i->ext.cvt.d);
|
||||
else
|
||||
if (i->def[0])
|
||||
nv_print_value(i->def[0], NULL, NV_OPTYPE(i->opcode));
|
||||
else
|
||||
if (i->target)
|
||||
PRINT(" %s(BB:%i)", yllw, i->target->id);
|
||||
else
|
||||
PRINT(" #");
|
||||
|
||||
for (s = 1; s < 4 && i->def[s]; ++s)
|
||||
nv_print_value(i->def[s], NULL, NV_OPTYPE(i->opcode));
|
||||
if (s > 1)
|
||||
PRINT("%s ,", norm);
|
||||
|
||||
for (s = 0; s < 6 && i->src[s]; ++s) {
|
||||
ubyte type;
|
||||
if (s == i->indirect || s == i->predicate)
|
||||
continue;
|
||||
if (i->opcode == NV_OP_CVT)
|
||||
type = i->ext.cvt.s;
|
||||
else
|
||||
type = NV_OPTYPE(i->opcode);
|
||||
|
||||
if (i->src[s]->mod)
|
||||
PRINT(" %s%s", gree, nv_modifier_string(i->src[s]->mod));
|
||||
|
||||
if (i->indirect >= 0 &&
|
||||
NV_IS_MEMORY_FILE(i->src[s]->value->reg.file))
|
||||
nv_print_ref(i->src[s], i->src[i->indirect]->value, type);
|
||||
else
|
||||
nv_print_ref(i->src[s], NULL, type);
|
||||
}
|
||||
PRINT(" %s\n", norm);
|
||||
}
|
||||
|
||||
#define NV_MOD_SGN_12 ((NV_MOD_ABS | NV_MOD_NEG) | ((NV_MOD_ABS | NV_MOD_NEG) << 4))
|
||||
#define NV_MOD_NEG_123 (NV_MOD_NEG | (NV_MOD_NEG << 4) | (NV_MOD_NEG << 8))
|
||||
#define NV_MOD_NEG_3 (NV_MOD_NEG << 8)
|
||||
|
||||
#define NV_MOD_SGN NV_MOD_SGN_12
|
||||
|
||||
struct nv_op_info nvc0_op_info_table[NV_OP_COUNT + 1] =
|
||||
{
|
||||
{ NV_OP_UNDEF, "undef", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 0, 0, 1, 0, 0 },
|
||||
{ NV_OP_BIND, "bind", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 1, 0, 1, 0, 0 },
|
||||
{ NV_OP_MERGE, "merge", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 1, 0, 1, 0, 0 },
|
||||
{ NV_OP_PHI, "phi", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 0, 0, 1, 0, 0 },
|
||||
{ NV_OP_SELECT, "select", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 0, 0, 1, 0, 0 },
|
||||
{ NV_OP_NOP, "nop", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_LD, "ld", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_ST, "st", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_MOV, "mov", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 1, 0 },
|
||||
{ NV_OP_AND, "and", NV_TYPE_U32, NV_MOD_NOT, 0, 1, 0, 1, 0, 6, 0 },
|
||||
{ NV_OP_OR, "or", NV_TYPE_U32, NV_MOD_NOT, 0, 1, 0, 1, 0, 6, 0 },
|
||||
{ NV_OP_XOR, "xor", NV_TYPE_U32, NV_MOD_NOT, 0, 1, 0, 1, 0, 6, 0 },
|
||||
{ NV_OP_SHL, "shl", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 1, 0 },
|
||||
{ NV_OP_SHR, "shr", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 1, 0 },
|
||||
{ NV_OP_NOT, "not", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_SET, "set", NV_TYPE_ANY, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_ADD, "add", NV_TYPE_F32, NV_MOD_SGN, 0, 1, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_SUB, "sub", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_MUL, "mul", NV_TYPE_F32, NV_MOD_NEG_123, 0, 1, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_MAD, "mad", NV_TYPE_F32, NV_MOD_NEG_123, 0, 1, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_ABS, "abs", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_NEG, "neg", NV_TYPE_F32, NV_MOD_ABS, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_MAX, "max", NV_TYPE_F32, NV_MOD_SGN, 0, 1, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_MIN, "min", NV_TYPE_F32, NV_MOD_SGN, 0, 1, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_CVT, "cvt", NV_TYPE_ANY, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_CEIL, "ceil", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_FLOOR, "floor", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_TRUNC, "trunc", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_SAD, "sad", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_VFETCH, "vfetch", NV_TYPE_ANY, 0, 0, 0, 1, 1, 0, 0, 0 },
|
||||
{ NV_OP_PFETCH, "pfetch", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_EXPORT, "export", NV_TYPE_ANY, 0, 0, 0, 1, 1, 0, 0, 0 },
|
||||
{ NV_OP_LINTERP, "linterp", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_PINTERP, "pinterp", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_EMIT, "emit", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_RESTART, "restart", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_TEX, "tex", NV_TYPE_F32, 0, 0, 0, 1, 1, 0, 0, 0 },
|
||||
{ NV_OP_TXB, "texbias", NV_TYPE_F32, 0, 0, 0, 1, 1, 0, 0, 0 },
|
||||
{ NV_OP_TXL, "texlod", NV_TYPE_F32, 0, 0, 0, 1, 1, 0, 0, 0 },
|
||||
{ NV_OP_TXF, "texfetch", NV_TYPE_U32, 0, 0, 0, 1, 1, 0, 0, 0 },
|
||||
{ NV_OP_TXQ, "texquery", NV_TYPE_U32, 0, 0, 0, 1, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_QUADOP, "quadop", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_DFDX, "dfdx", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_DFDY, "dfdy", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_KIL, "kil", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_BRA, "bra", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_CALL, "call", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_RET, "ret", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_RET, "exit", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_NOP, "ud", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_NOP, "ud", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_JOINAT, "joinat", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_JOIN, "join", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_ADD, "add", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 1, 0 },
|
||||
{ NV_OP_MUL, "mul", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 1, 0 },
|
||||
{ NV_OP_ABS, "abs", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_NEG, "neg", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_MAX, "max", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_MIN, "max", NV_TYPE_U32, 0, 0, 1, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_MAX, "min", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_MIN, "min", NV_TYPE_U32, 0, 0, 1, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_SET, "set", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_SET, "set", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_SET, "set", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_SHR, "sar", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 1, 0 },
|
||||
{ NV_OP_RCP, "rcp", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_RSQ, "rsqrt", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_LG2, "lg2", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_SIN, "sin", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_COS, "cos", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_EX2, "ex2", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_PRESIN, "presin", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 1 },
|
||||
{ NV_OP_PREEX2, "preex2", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 1 },
|
||||
{ NV_OP_SAT, "sat", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_SET_F32_AND, "and set", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_SET_F32_OR, "or set", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{ NV_OP_SET_F32_XOR, "xor set", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_SELP, "selp", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_SLCT, "slct", NV_TYPE_F32, NV_MOD_NEG_3, 0, 0, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_SLCT, "slct", NV_TYPE_S32, NV_MOD_NEG_3, 0, 0, 0, 1, 0, 2, 2 },
|
||||
{ NV_OP_SLCT, "slct", NV_TYPE_U32, NV_MOD_NEG_3, 0, 0, 0, 1, 0, 2, 2 },
|
||||
|
||||
{ NV_OP_ADD, "sub", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 1, 0 },
|
||||
|
||||
{ NV_OP_SET, "fset", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 2, 2 },
|
||||
|
||||
{ NV_OP_TXG, "texgrad", NV_TYPE_F32, 0, 0, 0, 1, 1, 0, 0, 0 },
|
||||
|
||||
{ NV_OP_UNDEF, "BAD_OP", NV_TYPE_ANY, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user