From e95e76e1255a3ad0ce604271301d090337b2e82b Mon Sep 17 00:00:00 2001 From: Nicolai Hähnle Date: Sun, 6 Sep 2009 11:47:40 +0200 Subject: r300/compiler: New dataflow structures and passes This replaces the old NQSSADCE code with the same functionality, but quite different design. Instead of doing a single integerated pass, we now build explicit data structures representing the dataflow. This will enable analysis of flow control instruction, and could potentially open an avenue for several dataflow based optimizations, such as peephole optimization, fusing MUL+ADD to MAD, and so on. --- src/mesa/drivers/dri/r300/compiler/Makefile | 8 +- .../dri/r300/compiler/r300_fragprog_swizzle.c | 35 +- .../dri/r300/compiler/r300_fragprog_swizzle.h | 7 +- src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c | 38 +-- src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c | 50 +-- src/mesa/drivers/dri/r300/compiler/r500_fragprog.c | 24 +- src/mesa/drivers/dri/r300/compiler/r500_fragprog.h | 6 +- .../drivers/dri/r300/compiler/radeon_compiler.c | 35 ++ .../drivers/dri/r300/compiler/radeon_compiler.h | 26 ++ .../drivers/dri/r300/compiler/radeon_dataflow.c | 106 ++++++ .../drivers/dri/r300/compiler/radeon_dataflow.h | 113 +++++++ .../dri/r300/compiler/radeon_dataflow_annotate.c | 365 +++++++++++++++++++++ .../dri/r300/compiler/radeon_dataflow_dealias.c | 150 +++++++++ .../dri/r300/compiler/radeon_dataflow_swizzles.c | 126 +++++++ .../drivers/dri/r300/compiler/radeon_nqssadce.c | 267 --------------- .../drivers/dri/r300/compiler/radeon_nqssadce.h | 92 ------ .../drivers/dri/r300/compiler/radeon_opcodes.c | 87 +++-- .../drivers/dri/r300/compiler/radeon_opcodes.h | 8 + .../drivers/dri/r300/compiler/radeon_program.c | 150 +-------- .../drivers/dri/r300/compiler/radeon_program.h | 110 +------ .../dri/r300/compiler/radeon_program_constants.h | 128 ++++++++ .../dri/r300/compiler/radeon_program_print.c | 214 ++++++++++++ .../drivers/dri/r300/compiler/radeon_swizzle.h | 57 ++++ src/mesa/drivers/dri/r300/r300_vertprog.c | 1 - 24 files changed, 1486 insertions(+), 717 deletions(-) create mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_dataflow.c create mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h create mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_dataflow_annotate.c create mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c create mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_dataflow_swizzles.c delete mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_nqssadce.c delete mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_nqssadce.h create mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_program_constants.h create mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_program_print.c create mode 100644 src/mesa/drivers/dri/r300/compiler/radeon_swizzle.h diff --git a/src/mesa/drivers/dri/r300/compiler/Makefile b/src/mesa/drivers/dri/r300/compiler/Makefile index 080c79898bf..53fb7caa95d 100644 --- a/src/mesa/drivers/dri/r300/compiler/Makefile +++ b/src/mesa/drivers/dri/r300/compiler/Makefile @@ -8,11 +8,15 @@ LIBNAME = r300compiler C_SOURCES = \ radeon_code.c \ radeon_compiler.c \ - radeon_nqssadce.c \ radeon_program.c \ - radeon_opcodes.c \ + radeon_program_print.c \ + radeon_opcodes.c \ radeon_program_alu.c \ radeon_program_pair.c \ + radeon_dataflow.c \ + radeon_dataflow_annotate.c \ + radeon_dataflow_dealias.c \ + radeon_dataflow_swizzles.c \ r3xx_fragprog.c \ r300_fragprog.c \ r300_fragprog_swizzle.c \ diff --git a/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c b/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c index ded6966d084..cfa48a59e3a 100644 --- a/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c +++ b/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c @@ -36,7 +36,6 @@ #include #include "../r300_reg.h" -#include "radeon_nqssadce.h" #include "radeon_compiler.h" #define MAKE_SWZ3(x, y, z) (RC_MAKE_SWIZZLE(RC_SWIZZLE_##x, RC_SWIZZLE_##y, RC_SWIZZLE_##z, RC_SWIZZLE_ZERO)) @@ -92,7 +91,7 @@ static const struct swizzle_data* lookup_native_swizzle(unsigned int swizzle) * Check whether the given instruction supports the swizzle and negate * combinations in the given source register. */ -int r300FPIsNativeSwizzle(rc_opcode opcode, struct rc_src_register reg) +static int r300_swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) { if (reg.Abs) reg.Negate = RC_MASK_NONE; @@ -134,15 +133,16 @@ int r300FPIsNativeSwizzle(rc_opcode opcode, struct rc_src_register reg) } -/** - * Generate MOV dst, src using only native swizzles. - */ -void r300FPBuildSwizzle(struct nqssadce_state *s, struct rc_dst_register dst, struct rc_src_register src) +static void r300_swizzle_split( + struct rc_src_register src, unsigned int mask, + struct rc_swizzle_split * split) { if (src.Abs) src.Negate = RC_MASK_NONE; - while(dst.WriteMask) { + split->NumPhases = 0; + + while(mask) { const struct swizzle_data *best_swizzle = 0; unsigned int best_matchcount = 0; unsigned int best_matchmask = 0; @@ -153,7 +153,7 @@ void r300FPBuildSwizzle(struct nqssadce_state *s, struct rc_dst_register dst, st unsigned int matchcount = 0; unsigned int matchmask = 0; for(comp = 0; comp < 3; ++comp) { - if (!GET_BIT(dst.WriteMask, comp)) + if (!GET_BIT(mask, comp)) continue; unsigned int swz = GET_SWZ(src.Swizzle, comp); if (swz == RC_SWIZZLE_UNUSED) @@ -172,23 +172,24 @@ void r300FPBuildSwizzle(struct nqssadce_state *s, struct rc_dst_register dst, st best_swizzle = sd; best_matchcount = matchcount; best_matchmask = matchmask; - if (matchmask == (dst.WriteMask & RC_MASK_XYZ)) + if (matchmask == (mask & RC_MASK_XYZ)) break; } } - struct rc_instruction *inst = rc_insert_new_instruction(s->Compiler, s->IP->Prev); - inst->I.Opcode = RC_OPCODE_MOV; - inst->I.DstReg = dst; - inst->I.DstReg.WriteMask &= (best_matchmask | RC_MASK_W); - inst->I.SrcReg[0] = src; - inst->I.SrcReg[0].Negate = (best_matchmask & src.Negate) ? RC_MASK_XYZW : RC_MASK_NONE; - /* Note: We rely on NqSSA/DCE to set unused swizzle components to NIL */ + if (mask & RC_MASK_W) + best_matchmask |= RC_MASK_W; - dst.WriteMask &= ~inst->I.DstReg.WriteMask; + split->Phase[split->NumPhases++] = best_matchmask; + mask &= ~best_matchmask; } } +struct rc_swizzle_caps r300_swizzle_caps = { + .IsNative = r300_swizzle_is_native, + .Split = r300_swizzle_split +}; + /** * Translate an RGB (XYZ) swizzle into the hardware code for the given diff --git a/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h b/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h index 728c2cd972f..118476af132 100644 --- a/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h +++ b/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h @@ -28,12 +28,9 @@ #ifndef __R300_FRAGPROG_SWIZZLE_H_ #define __R300_FRAGPROG_SWIZZLE_H_ -#include "radeon_program.h" +#include "radeon_swizzle.h" -struct nqssadce_state; - -int r300FPIsNativeSwizzle(rc_opcode opcode, struct rc_src_register reg); -void r300FPBuildSwizzle(struct nqssadce_state*, struct rc_dst_register dst, struct rc_src_register src); +extern struct rc_swizzle_caps r300_swizzle_caps; unsigned int r300FPTranslateRGBSwizzle(unsigned int src, unsigned int swizzle); unsigned int r300FPTranslateAlphaSwizzle(unsigned int src, unsigned int swizzle); diff --git a/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c b/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c index 0aa40c05876..bf9bea685ab 100644 --- a/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c +++ b/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c @@ -24,18 +24,18 @@ #include -#include "radeon_nqssadce.h" #include "radeon_program_alu.h" #include "r300_fragprog.h" #include "r300_fragprog_swizzle.h" #include "r500_fragprog.h" -static void nqssadce_init(struct nqssadce_state* s) +static void dataflow_outputs_mark_use(void * userdata, void * data, + void (*callback)(void *, unsigned int, unsigned int)) { - struct r300_fragment_program_compiler * c = s->UserData; - s->Outputs[c->OutputColor].Sourced = RC_MASK_XYZW; - s->Outputs[c->OutputDepth].Sourced = RC_MASK_W; + struct r300_fragment_program_compiler * c = userdata; + callback(data, c->OutputColor, RC_MASK_XYZW); + callback(data, c->OutputDepth, RC_MASK_W); } static void rewrite_depth_out(struct r300_fragment_program_compiler * c) @@ -92,6 +92,8 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c) { &radeonTransformTrigScale, 0 } }; radeonLocalTransform(&c->Base, 4, transformations); + + c->Base.SwizzleCaps = &r500_swizzle_caps; } else { struct radeon_program_transformation transformations[] = { { &r300_transform_TEX, c }, @@ -99,33 +101,23 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c) { &radeonTransformTrigSimple, 0 } }; radeonLocalTransform(&c->Base, 3, transformations); + + c->Base.SwizzleCaps = &r300_swizzle_caps; } if (c->Base.Debug) { fprintf(stderr, "Fragment Program: After native rewrite:\n"); - rc_print_program(&c->Base.Program); + rc_print_program(&c->Base.Program, 0); fflush(stderr); } - if (c->is_r500) { - struct radeon_nqssadce_descr nqssadce = { - .Init = &nqssadce_init, - .IsNativeSwizzle = &r500FPIsNativeSwizzle, - .BuildSwizzle = &r500FPBuildSwizzle - }; - radeonNqssaDce(&c->Base, &nqssadce, c); - } else { - struct radeon_nqssadce_descr nqssadce = { - .Init = &nqssadce_init, - .IsNativeSwizzle = &r300FPIsNativeSwizzle, - .BuildSwizzle = &r300FPBuildSwizzle - }; - radeonNqssaDce(&c->Base, &nqssadce, c); - } + rc_dataflow_annotate(&c->Base, &dataflow_outputs_mark_use, c); + rc_dataflow_dealias(&c->Base); + rc_dataflow_swizzles(&c->Base); if (c->Base.Debug) { - fprintf(stderr, "Compiler: after NqSSA-DCE:\n"); - rc_print_program(&c->Base.Program); + fprintf(stderr, "Compiler: after dataflow passes:\n"); + rc_print_program(&c->Base.Program, 0); fflush(stderr); } diff --git a/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c b/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c index 0efd2c91e6a..c64648ff3b5 100644 --- a/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c +++ b/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c @@ -26,9 +26,9 @@ #include "../r300_reg.h" -#include "radeon_nqssadce.h" -#include "radeon_program.h" +#include "radeon_dataflow.h" #include "radeon_program_alu.h" +#include "radeon_swizzle.h" /* @@ -545,18 +545,19 @@ static void addArtificialOutputs(struct r300_vertex_program_compiler * compiler) } } -static void nqssadceInit(struct nqssadce_state* s) +static void dataflow_outputs_mark_used(void * userdata, void * data, + void (*callback)(void *, unsigned int, unsigned int)) { - struct r300_vertex_program_compiler * compiler = s->UserData; + struct r300_vertex_program_compiler * c = userdata; int i; for(i = 0; i < 32; ++i) { - if (compiler->RequiredOutputs & (1 << i)) - s->Outputs[i].Sourced = RC_MASK_XYZW; + if (c->RequiredOutputs & (1 << i)) + callback(data, i, RC_MASK_XYZW); } } -static int swizzleIsNative(rc_opcode opcode, struct rc_src_register reg) +static int swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) { (void) opcode; (void) reg; @@ -565,9 +566,16 @@ static int swizzleIsNative(rc_opcode opcode, struct rc_src_register reg) } +static struct rc_swizzle_caps r300_vertprog_swizzle_caps = { + .IsNative = &swizzle_is_native, + .Split = 0 /* should never be called */ +}; + void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler) { + compiler->Base.SwizzleCaps = &r300_vertprog_swizzle_caps; + addArtificialOutputs(compiler); { @@ -579,7 +587,7 @@ void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler) if (compiler->Base.Debug) { fprintf(stderr, "Vertex program after native rewrite:\n"); - rc_print_program(&compiler->Base.Program); + rc_print_program(&compiler->Base.Program, 0); fflush(stderr); } @@ -596,26 +604,22 @@ void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler) if (compiler->Base.Debug) { fprintf(stderr, "Vertex program after source conflict resolve:\n"); - rc_print_program(&compiler->Base.Program); + rc_print_program(&compiler->Base.Program, 0); fflush(stderr); } - { - struct radeon_nqssadce_descr nqssadce = { - .Init = &nqssadceInit, - .IsNativeSwizzle = &swizzleIsNative, - .BuildSwizzle = NULL - }; - radeonNqssaDce(&compiler->Base, &nqssadce, compiler); + rc_dataflow_annotate(&compiler->Base, &dataflow_outputs_mark_used, compiler); + rc_dataflow_dealias(&compiler->Base); + rc_dataflow_swizzles(&compiler->Base); - /* We need this step for reusing temporary registers */ - allocate_temporary_registers(compiler); + /* This invalidates dataflow annotations and should be replaced + * by a future generic register allocation pass. */ + allocate_temporary_registers(compiler); - if (compiler->Base.Debug) { - fprintf(stderr, "Vertex program after NQSSADCE:\n"); - rc_print_program(&compiler->Base.Program); - fflush(stderr); - } + if (compiler->Base.Debug) { + fprintf(stderr, "Vertex program after dataflow:\n"); + rc_print_program(&compiler->Base.Program, 0); + fflush(stderr); } translate_vertex_program(compiler); diff --git a/src/mesa/drivers/dri/r300/compiler/r500_fragprog.c b/src/mesa/drivers/dri/r300/compiler/r500_fragprog.c index 3e994ebd1b5..971465e3591 100644 --- a/src/mesa/drivers/dri/r300/compiler/r500_fragprog.c +++ b/src/mesa/drivers/dri/r300/compiler/r500_fragprog.c @@ -169,7 +169,7 @@ int r500_transform_TEX( return 1; } -int r500FPIsNativeSwizzle(rc_opcode opcode, struct rc_src_register reg) +static int r500_swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) { unsigned int relevant; int i; @@ -227,36 +227,38 @@ int r500FPIsNativeSwizzle(rc_opcode opcode, struct rc_src_register reg) } /** - * Implement a MOV with a potentially non-native swizzle. + * Split source register access. * * The only thing we *cannot* do in an ALU instruction is per-component - * negation. Therefore, we split the MOV into two instructions when necessary. + * negation. */ -void r500FPBuildSwizzle(struct nqssadce_state *s, struct rc_dst_register dst, struct rc_src_register src) +static void r500_swizzle_split(struct rc_src_register src, unsigned int usemask, + struct rc_swizzle_split * split) { unsigned int negatebase[2] = { 0, 0 }; int i; for(i = 0; i < 4; ++i) { unsigned int swz = GET_SWZ(src.Swizzle, i); - if (swz == RC_SWIZZLE_UNUSED) + if (swz == RC_SWIZZLE_UNUSED || !GET_BIT(usemask, i)) continue; negatebase[GET_BIT(src.Negate, i)] |= 1 << i; } + split->NumPhases = 0; + for(i = 0; i <= 1; ++i) { if (!negatebase[i]) continue; - struct rc_instruction *inst = rc_insert_new_instruction(s->Compiler, s->IP->Prev); - inst->I.Opcode = RC_OPCODE_MOV; - inst->I.DstReg = dst; - inst->I.DstReg.WriteMask = negatebase[i]; - inst->I.SrcReg[0] = src; - inst->I.SrcReg[0].Negate = (i == 0) ? RC_MASK_NONE : RC_MASK_XYZW; + split->Phase[split->NumPhases++] = negatebase[i]; } } +struct rc_swizzle_caps r500_swizzle_caps = { + .IsNative = r500_swizzle_is_native, + .Split = r500_swizzle_split +}; static char *toswiz(int swiz_val) { switch(swiz_val) { diff --git a/src/mesa/drivers/dri/r300/compiler/r500_fragprog.h b/src/mesa/drivers/dri/r300/compiler/r500_fragprog.h index 887d4abbd25..92ac75d5fd4 100644 --- a/src/mesa/drivers/dri/r300/compiler/r500_fragprog.h +++ b/src/mesa/drivers/dri/r300/compiler/r500_fragprog.h @@ -34,15 +34,13 @@ #define __R500_FRAGPROG_H_ #include "radeon_compiler.h" -#include "radeon_nqssadce.h" +#include "radeon_swizzle.h" extern void r500BuildFragmentProgramHwCode(struct r300_fragment_program_compiler *compiler); extern void r500FragmentProgramDump(struct rX00_fragment_program_code *c); -extern int r500FPIsNativeSwizzle(rc_opcode opcode, struct rc_src_register reg); - -extern void r500FPBuildSwizzle(struct nqssadce_state *s, struct rc_dst_register dst, struct rc_src_register src); +extern struct rc_swizzle_caps r500_swizzle_caps; extern int r500_transform_TEX( struct radeon_compiler * c, diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_compiler.c b/src/mesa/drivers/dri/r300/compiler/radeon_compiler.c index babdcffd3ab..d0b78ec1c88 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_compiler.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_compiler.c @@ -93,6 +93,41 @@ void rc_error(struct radeon_compiler * c, const char * fmt, ...) } } +int rc_if_fail_helper(struct radeon_compiler * c, const char * file, int line, const char * assertion) +{ + rc_error(c, "ICE at %s:%i: assertion failed: %s\n", file, line, assertion); + return 1; +} + +/** + * Recompute c->Program.InputsRead and c->Program.OutputsWritten + * based on which inputs and outputs are actually referenced + * in program instructions. + */ +void rc_calculate_inputs_outputs(struct radeon_compiler * c) +{ + struct rc_instruction *inst; + + c->Program.InputsRead = 0; + c->Program.OutputsWritten = 0; + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) + { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); + int i; + + for (i = 0; i < opcode->NumSrcRegs; ++i) { + if (inst->I.SrcReg[i].File == RC_FILE_INPUT) + c->Program.InputsRead |= 1 << inst->I.SrcReg[i].Index; + } + + if (opcode->HasDstReg) { + if (inst->I.DstReg.File == RC_FILE_OUTPUT) + c->Program.OutputsWritten |= 1 << inst->I.DstReg.Index; + } + } +} + /** * Rewrite the program such that everything that source the given input * register will source new_input instead. diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_compiler.h b/src/mesa/drivers/dri/r300/compiler/radeon_compiler.h index 018f9bba06a..87a732cd90d 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_compiler.h +++ b/src/mesa/drivers/dri/r300/compiler/radeon_compiler.h @@ -27,6 +27,7 @@ #include "radeon_code.h" #include "radeon_program.h" +struct rc_swizzle_caps; struct radeon_compiler { struct memory_pool Pool; @@ -34,6 +35,14 @@ struct radeon_compiler { unsigned Debug:1; unsigned Error:1; char * ErrorMsg; + + /** + * Variables used internally, not be touched by callers + * of the compiler + */ + /*@{*/ + struct rc_swizzle_caps * SwizzleCaps; + /*@}*/ }; void rc_init(struct radeon_compiler * c); @@ -42,6 +51,23 @@ void rc_destroy(struct radeon_compiler * c); void rc_debug(struct radeon_compiler * c, const char * fmt, ...); void rc_error(struct radeon_compiler * c, const char * fmt, ...); +int rc_if_fail_helper(struct radeon_compiler * c, const char * file, int line, const char * assertion); + +/** + * This macro acts like an if-statement that can be used to implement + * non-aborting assertions in the compiler. + * + * It checks whether \p cond is true. If not, an internal compiler error is + * flagged and the if-clause is run. + * + * A typical use-case would be: + * + * if (rc_assert(c, condition-that-must-be-true)) + * return; + */ +#define rc_assert(c, cond) \ + (!(cond) && rc_if_fail_helper(c, __FILE__, __LINE__, #cond)) + void rc_calculate_inputs_outputs(struct radeon_compiler * c); void rc_move_input(struct radeon_compiler * c, unsigned input, struct rc_src_register new_input); diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.c b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.c new file mode 100644 index 00000000000..af6777a7bd3 --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 "radeon_dataflow.h" + +#include "radeon_compiler.h" + + +static void add_ref_to_vector(struct rc_dataflow_ref * ref, struct rc_dataflow_vector * vector) +{ + ref->Vector = vector; + ref->Prev = &vector->Refs; + ref->Next = vector->Refs.Next; + ref->Prev->Next = ref; + ref->Next->Prev = ref; +} + +struct rc_dataflow_ref * rc_dataflow_create_ref(struct radeon_compiler * c, + struct rc_dataflow_vector * vector, struct rc_instruction * inst) +{ + struct rc_dataflow_ref * ref = memory_pool_malloc(&c->Pool, sizeof(struct rc_dataflow_ref)); + ref->ReadInstruction = inst; + ref->UseMask = 0; + + add_ref_to_vector(ref, vector); + + return ref; +} + +struct rc_dataflow_vector * rc_dataflow_create_vector(struct radeon_compiler * c, + rc_register_file file, unsigned int index, struct rc_instruction * inst) +{ + struct rc_dataflow_vector * vec = memory_pool_malloc(&c->Pool, sizeof(struct rc_dataflow_vector)); + + memset(vec, 0, sizeof(struct rc_dataflow_vector)); + vec->File = file; + vec->Index = index; + vec->WriteInstruction = inst; + + vec->Refs.Next = vec->Refs.Prev = &vec->Refs; + + return vec; +} + +void rc_dataflow_remove_ref(struct rc_dataflow_ref * ref) +{ + ref->Prev->Next = ref->Next; + ref->Next->Prev = ref->Prev; +} + +void rc_dataflow_remove_instruction(struct rc_instruction * inst) +{ + for(unsigned int i = 0; i < 3; ++i) { + if (inst->Dataflow.SrcReg[i]) { + rc_dataflow_remove_ref(inst->Dataflow.SrcReg[i]); + inst->Dataflow.SrcReg[i] = 0; + } + if (inst->Dataflow.SrcRegAddress[i]) { + rc_dataflow_remove_ref(inst->Dataflow.SrcRegAddress[i]); + inst->Dataflow.SrcRegAddress[i] = 0; + } + } + + if (inst->Dataflow.DstReg) { + while(inst->Dataflow.DstReg->Refs.Next != &inst->Dataflow.DstReg->Refs) { + struct rc_dataflow_ref * ref = inst->Dataflow.DstReg->Refs.Next; + rc_dataflow_remove_ref(ref); + if (inst->Dataflow.DstRegPrev) + add_ref_to_vector(ref, inst->Dataflow.DstRegPrev->Vector); + } + + inst->Dataflow.DstReg->WriteInstruction = 0; + inst->Dataflow.DstReg = 0; + } + + if (inst->Dataflow.DstRegPrev) { + rc_dataflow_remove_ref(inst->Dataflow.DstRegPrev); + inst->Dataflow.DstRegPrev = 0; + } + + inst->Dataflow.DstRegAliased = 0; +} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h new file mode 100644 index 00000000000..c9856affe88 --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 RADEON_DATAFLOW_H +#define RADEON_DATAFLOW_H + +#include "radeon_program_constants.h" + +struct radeon_compiler; +struct rc_instruction; +struct rc_swizzle_caps; + +struct rc_dataflow_vector; + +struct rc_dataflow_ref { + struct rc_dataflow_vector * Vector; + + /** + * Linked list of references to the above-mentioned vector. + * The linked list is \em not sorted. + */ + /*@{*/ + struct rc_dataflow_ref * Prev; + struct rc_dataflow_ref * Next; + /*@}*/ + + unsigned int UseMask:4; + struct rc_instruction * ReadInstruction; +}; + +struct rc_dataflow_vector { + rc_register_file File:3; + unsigned int Index:RC_REGISTER_INDEX_BITS; + + /** For private use in compiler passes. MUST BE RESET TO 0 by the end of each pass. + * The annotate pass uses this bit to track whether a vector is in the + * update stack. + */ + unsigned int PassBit:1; + /** Which of the components have been written with useful values */ + unsigned int ValidMask:4; + /** Which of the components are used downstream */ + unsigned int UseMask:4; + /** The instruction that produced this vector */ + struct rc_instruction * WriteInstruction; + + /** Linked list of references to this vector */ + struct rc_dataflow_ref Refs; +}; + +struct rc_instruction_dataflow { + struct rc_dataflow_ref * SrcReg[3]; + struct rc_dataflow_ref * SrcRegAddress[3]; + + /** Reference the components of the destination register + * that are carried over without being overwritten */ + struct rc_dataflow_ref * DstRegPrev; + /** Indicates whether the destination register was in use + * before this instruction */ + unsigned int DstRegAliased:1; + struct rc_dataflow_vector * DstReg; +}; + +/** + * General functions for manipulating the dataflow structures. + */ +/*@{*/ +struct rc_dataflow_ref * rc_dataflow_create_ref(struct radeon_compiler * c, + struct rc_dataflow_vector * vector, struct rc_instruction * inst); +struct rc_dataflow_vector * rc_dataflow_create_vector(struct radeon_compiler * c, + rc_register_file file, unsigned int index, struct rc_instruction * inst); +void rc_dataflow_remove_ref(struct rc_dataflow_ref * ref); + +void rc_dataflow_remove_instruction(struct rc_instruction * inst); +/*@}*/ + + +/** + * Compiler passes based on dataflow structures. + */ +/*@{*/ +typedef void (*rc_dataflow_mark_outputs_fn)(void * userdata, void * data, + void (*mark_fn)(void * data, unsigned int index, unsigned int mask)); +void rc_dataflow_annotate(struct radeon_compiler * c, rc_dataflow_mark_outputs_fn dce, void * userdata); +void rc_dataflow_dealias(struct radeon_compiler * c); +void rc_dataflow_swizzles(struct radeon_compiler * c); +/*@}*/ + +#endif /* RADEON_DATAFLOW_H */ diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_annotate.c b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_annotate.c new file mode 100644 index 00000000000..41d175a22f2 --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_annotate.c @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 "radeon_dataflow.h" + +#include "radeon_compiler.h" + + +struct dataflow_state { + struct radeon_compiler * C; + unsigned int DCE:1; + unsigned int UpdateRunning:1; + + struct rc_dataflow_vector * Input[RC_REGISTER_MAX_INDEX]; + struct rc_dataflow_vector * Output[RC_REGISTER_MAX_INDEX]; + struct rc_dataflow_vector * Temporary[RC_REGISTER_MAX_INDEX]; + struct rc_dataflow_vector * Address; + + struct rc_dataflow_vector ** UpdateStack; + unsigned int UpdateStackSize; + unsigned int UpdateStackReserved; +}; + +static void mark_vector_use(struct dataflow_state * s, struct rc_dataflow_vector * vector, unsigned int mask); + +static struct rc_dataflow_vector * get_register_contents(struct dataflow_state * s, + rc_register_file file, unsigned int index) +{ + if (file == RC_FILE_INPUT || file == RC_FILE_OUTPUT || file == RC_FILE_TEMPORARY) { + if (index >= RC_REGISTER_MAX_INDEX) + return 0; /* cannot happen, but be defensive */ + + if (file == RC_FILE_TEMPORARY) + return s->Temporary[index]; + if (file == RC_FILE_INPUT) + return s->Input[index]; + if (file == RC_FILE_OUTPUT) + return s->Output[index]; + } + + if (file == RC_FILE_ADDRESS) + return s->Address; + + return 0; /* can happen, constant register file */ +} + +static void mark_ref_use(struct dataflow_state * s, struct rc_dataflow_ref * ref, unsigned int mask) +{ + if (!(mask & ~ref->UseMask)) + return; + + ref->UseMask |= mask; + mark_vector_use(s, ref->Vector, ref->UseMask); +} + +static void mark_source_use(struct dataflow_state * s, struct rc_instruction * inst, + unsigned int src, unsigned int srcmask) +{ + unsigned int refmask = 0; + + for(unsigned int i = 0; i < 4; ++i) { + if (GET_BIT(srcmask, i)) + refmask |= 1 << GET_SWZ(inst->I.SrcReg[src].Swizzle, i); + } + + /* get rid of spurious bits from ZERO, ONE, etc. swizzles */ + refmask &= RC_MASK_XYZW; + + if (!refmask) + return; /* can happen if the swizzle contains constant components */ + + if (inst->Dataflow.SrcReg[src]) + mark_ref_use(s, inst->Dataflow.SrcReg[src], refmask); + + if (inst->Dataflow.SrcRegAddress[src]) + mark_ref_use(s, inst->Dataflow.SrcRegAddress[src], RC_MASK_X); +} + +static void compute_sources_for_writemask( + struct rc_instruction * inst, + unsigned int writemask, + unsigned int *srcmasks) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); + + srcmasks[0] = 0; + srcmasks[1] = 0; + srcmasks[2] = 0; + + if (inst->I.Opcode == RC_OPCODE_KIL) + srcmasks[0] |= RC_MASK_XYZW; + + if (!writemask) + return; + + if (opcode->IsComponentwise) { + for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) + srcmasks[src] |= writemask; + } else if (opcode->IsStandardScalar) { + for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) + srcmasks[src] |= RC_MASK_X; + } else { + switch(inst->I.Opcode) { + case RC_OPCODE_ARL: + srcmasks[0] |= RC_MASK_X; + break; + case RC_OPCODE_DP3: + srcmasks[0] |= RC_MASK_XYZ; + srcmasks[1] |= RC_MASK_XYZ; + break; + case RC_OPCODE_DP4: + srcmasks[0] |= RC_MASK_XYZW; + srcmasks[1] |= RC_MASK_XYZW; + break; + case RC_OPCODE_TEX: + case RC_OPCODE_TXB: + case RC_OPCODE_TXP: + srcmasks[0] |= RC_MASK_XYZW; + break; + case RC_OPCODE_DST: + srcmasks[0] |= 0x6; + srcmasks[1] |= 0xa; + break; + case RC_OPCODE_EXP: + case RC_OPCODE_LOG: + srcmasks[0] |= RC_MASK_XY; + break; + case RC_OPCODE_LIT: + srcmasks[0] |= 0xb; + break; + default: + break; + } + } +} + +static void mark_instruction_source_use(struct dataflow_state * s, + struct rc_instruction * inst, unsigned int writemask) +{ + unsigned int srcmasks[3]; + + compute_sources_for_writemask(inst, writemask, srcmasks); + + for(unsigned int src = 0; src < 3; ++src) + mark_source_use(s, inst, src, srcmasks[src]); +} + +static void run_update(struct dataflow_state * s) +{ + s->UpdateRunning = 1; + + while(s->UpdateStackSize) { + struct rc_dataflow_vector * vector = s->UpdateStack[--s->UpdateStackSize]; + vector->PassBit = 0; + + if (vector->WriteInstruction) { + struct rc_instruction * inst = vector->WriteInstruction; + + if (inst->Dataflow.DstRegPrev) { + unsigned int carryover = vector->UseMask & ~inst->I.DstReg.WriteMask; + + if (carryover) + mark_ref_use(s, inst->Dataflow.DstRegPrev, carryover); + } + + mark_instruction_source_use( + s, vector->WriteInstruction, + vector->UseMask & inst->I.DstReg.WriteMask); + } + } + + s->UpdateRunning = 0; +} + +static void mark_vector_use(struct dataflow_state * s, struct rc_dataflow_vector * vector, unsigned int mask) +{ + if (!(mask & ~vector->UseMask)) + return; /* no new used bits */ + + vector->UseMask |= mask; + if (vector->PassBit) + return; + + if (s->UpdateStackSize >= s->UpdateStackReserved) { + unsigned int new_reserve = 2 * s->UpdateStackReserved; + struct rc_dataflow_vector ** new_stack; + + if (!new_reserve) + new_reserve = 16; + + new_stack = memory_pool_malloc(&s->C->Pool, new_reserve * sizeof(struct rc_dataflow_vector *)); + memcpy(new_stack, s->UpdateStack, s->UpdateStackSize * sizeof(struct rc_dataflow_vector *)); + + s->UpdateStack = new_stack; + s->UpdateStackReserved = new_reserve; + } + + s->UpdateStack[s->UpdateStackSize++] = vector; + vector->PassBit = 1; + + if (!s->UpdateRunning) + run_update(s); +} + +static void annotate_instruction(struct dataflow_state * s, struct rc_instruction * inst) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); + unsigned int src; + + for(src = 0; src < opcode->NumSrcRegs; ++src) { + struct rc_dataflow_vector * vector = get_register_contents(s, inst->I.SrcReg[src].File, inst->I.SrcReg[src].Index); + if (vector) { + inst->Dataflow.SrcReg[src] = rc_dataflow_create_ref(s->C, vector, inst); + } + if (inst->I.SrcReg[src].RelAddr) { + struct rc_dataflow_vector * addr = get_register_contents(s, RC_FILE_ADDRESS, 0); + if (addr) + inst->Dataflow.SrcRegAddress[src] = rc_dataflow_create_ref(s->C, addr, inst); + } + } + + mark_instruction_source_use(s, inst, 0); /* for KIL */ + + if (opcode->HasDstReg) { + struct rc_dataflow_vector * oldvec = get_register_contents(s, inst->I.DstReg.File, inst->I.DstReg.Index); + struct rc_dataflow_vector * newvec = rc_dataflow_create_vector(s->C, inst->I.DstReg.File, inst->I.DstReg.Index, inst); + + newvec->ValidMask = inst->I.DstReg.WriteMask; + + if (oldvec) { + unsigned int carryover = oldvec->ValidMask & ~inst->I.DstReg.WriteMask; + + if (oldvec->ValidMask) + inst->Dataflow.DstRegAliased = 1; + + if (carryover) { + inst->Dataflow.DstRegPrev = rc_dataflow_create_ref(s->C, oldvec, inst); + newvec->ValidMask |= carryover; + + if (!s->DCE) + mark_ref_use(s, inst->Dataflow.DstRegPrev, carryover); + } + } + + inst->Dataflow.DstReg = newvec; + + if (newvec->File == RC_FILE_TEMPORARY) + s->Temporary[newvec->Index] = newvec; + else if (newvec->File == RC_FILE_OUTPUT) + s->Output[newvec->Index] = newvec; + else + s->Address = newvec; + + if (!s->DCE) + mark_vector_use(s, newvec, inst->I.DstReg.WriteMask); + } +} + +static void init_inputs(struct dataflow_state * s) +{ + unsigned int index; + + for(index = 0; index < 32; ++index) { + if (s->C->Program.InputsRead & (1 << index)) { + s->Input[index] = rc_dataflow_create_vector(s->C, RC_FILE_INPUT, index, 0); + s->Input[index]->ValidMask = RC_MASK_XYZW; + } + } +} + +static void mark_output_use(void * data, unsigned int index, unsigned int mask) +{ + struct dataflow_state * s = data; + struct rc_dataflow_vector * vec = s->Output[index]; + + if (vec) + mark_vector_use(s, vec, mask); +} + +void rc_dataflow_annotate(struct radeon_compiler * c, rc_dataflow_mark_outputs_fn dce, void * userdata) +{ + struct dataflow_state s; + struct rc_instruction * inst; + + memset(&s, 0, sizeof(s)); + s.C = c; + s.DCE = dce ? 1 : 0; + + init_inputs(&s); + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { + annotate_instruction(&s, inst); + } + + if (s.DCE) { + dce(userdata, &s, &mark_output_use); + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); + + if (opcode->HasDstReg) { + unsigned int redundant_writes = inst->I.DstReg.WriteMask & ~inst->Dataflow.DstReg->UseMask; + + inst->I.DstReg.WriteMask &= ~redundant_writes; + + if (!inst->I.DstReg.WriteMask) { + struct rc_instruction * todelete = inst; + inst = inst->Prev; + rc_remove_instruction(todelete); + continue; + } + } + + unsigned int srcmasks[3]; + compute_sources_for_writemask(inst, inst->I.DstReg.WriteMask, srcmasks); + + for(unsigned int src = 0; src < 3; ++src) { + for(unsigned int chan = 0; chan < 4; ++chan) { + if (!GET_BIT(srcmasks[src], chan)) + SET_SWZ(inst->I.SrcReg[src].Swizzle, chan, RC_SWIZZLE_UNUSED); + } + + if (inst->Dataflow.SrcReg[src]) { + if (!inst->Dataflow.SrcReg[src]->UseMask) { + rc_dataflow_remove_ref(inst->Dataflow.SrcReg[src]); + inst->Dataflow.SrcReg[src] = 0; + } + } + + if (inst->Dataflow.SrcRegAddress[src]) { + if (!inst->Dataflow.SrcRegAddress[src]->UseMask) { + rc_dataflow_remove_ref(inst->Dataflow.SrcRegAddress[src]); + inst->Dataflow.SrcRegAddress[src] = 0; + } + } + } + } + + rc_calculate_inputs_outputs(c); + } +} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c new file mode 100644 index 00000000000..4596636970a --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 "radeon_dataflow.h" + +#include "radeon_compiler.h" + + +#define DEALIAS_LIST_SIZE 128 + +struct dealias_state { + struct radeon_compiler * C; + + unsigned int OldIndex:RC_REGISTER_INDEX_BITS; + unsigned int NewIndex:RC_REGISTER_INDEX_BITS; + unsigned int DealiasFail:1; + + struct rc_dataflow_vector * List[DEALIAS_LIST_SIZE]; + unsigned int Length; +}; + +static void push_dealias_vector(struct dealias_state * s, struct rc_dataflow_vector * vec) +{ + if (s->Length >= DEALIAS_LIST_SIZE) { + rc_debug(s->C, "%s: list size exceeded\n", __FUNCTION__); + s->DealiasFail = 1; + return; + } + + if (rc_assert(s->C, vec->File == RC_FILE_TEMPORARY && vec->Index == s->OldIndex)) + return; + + s->List[s->Length++] = vec; +} + +static void run_dealias(struct dealias_state * s) +{ + unsigned int i; + + for(i = 0; i < s->Length && !s->DealiasFail; ++i) { + struct rc_dataflow_vector * vec = s->List[i]; + struct rc_dataflow_ref * ref; + + for(ref = vec->Refs.Next; ref != &vec->Refs; ref = ref->Next) { + if (ref->ReadInstruction->Dataflow.DstRegPrev == ref) + push_dealias_vector(s, ref->ReadInstruction->Dataflow.DstReg); + } + } + + if (s->DealiasFail) + return; + + for(i = 0; i < s->Length; ++i) { + struct rc_dataflow_vector * vec = s->List[i]; + struct rc_dataflow_ref * ref; + + vec->Index = s->NewIndex; + vec->WriteInstruction->I.DstReg.Index = s->NewIndex; + + for(ref = vec->Refs.Next; ref != &vec->Refs; ref = ref->Next) { + struct rc_instruction * inst = ref->ReadInstruction; + unsigned int i; + + for(i = 0; i < 3; ++i) { + if (inst->Dataflow.SrcReg[i] == ref) { + if (rc_assert(s->C, inst->I.SrcReg[i].File == RC_FILE_TEMPORARY && + inst->I.SrcReg[i].Index == s->OldIndex)) + return; + + inst->I.SrcReg[i].Index = s->NewIndex; + } + } + } + } +} + +/** + * Breaks register aliasing to reduce multiple assignments to a single register. + * + * This affects sequences like: + * MUL r0, ...; + * MAD r0, r1, r2, r0; + * In this example, a new register will be used for the destination of the + * second MAD. + * + * The purpose of this dealiasing is to make the resulting code more SSA-like + * and therefore make it easier to move instructions around. + * This is of crucial importance for R300 fragment programs, where de-aliasing + * can help to reduce texture indirections, but other targets can benefit from + * it as well. + * + * \note When compiling GLSL, there may be some benefit gained from breaking + * up vectors whose components are unrelated. This is not done yet and should + * be investigated at some point (of course, a matching pass to re-merge + * components would be required). + */ +void rc_dataflow_dealias(struct radeon_compiler * c) +{ + struct dealias_state s; + + memset(&s, 0, sizeof(s)); + s.C = c; + + struct rc_instruction * inst; + for(inst = c->Program.Instructions.Prev; inst != &c->Program.Instructions; inst = inst->Prev) { + if (!inst->Dataflow.DstRegAliased || inst->Dataflow.DstReg->File != RC_FILE_TEMPORARY) + continue; + + if (inst->Dataflow.DstReg->UseMask & ~inst->I.DstReg.WriteMask) + continue; + + s.OldIndex = inst->I.DstReg.Index; + s.NewIndex = rc_find_free_temporary(c); + s.DealiasFail = 0; + s.Length = 0; + + inst->Dataflow.DstRegAliased = 0; + if (inst->Dataflow.DstRegPrev) { + rc_dataflow_remove_ref(inst->Dataflow.DstRegPrev); + inst->Dataflow.DstRegPrev = 0; + } + + push_dealias_vector(&s, inst->Dataflow.DstReg); + run_dealias(&s); + } +} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_swizzles.c b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_swizzles.c new file mode 100644 index 00000000000..1aa91eff7c1 --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_swizzles.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 "radeon_dataflow.h" + +#include "radeon_compiler.h" +#include "radeon_swizzle.h" + + +static void rewrite_source(struct radeon_compiler * c, + struct rc_instruction * inst, unsigned src) +{ + struct rc_swizzle_split split; + unsigned int tempreg = rc_find_free_temporary(c); + unsigned int usemask; + struct rc_dataflow_ref * oldref = inst->Dataflow.SrcReg[src]; + struct rc_dataflow_vector * vector = 0; + + usemask = 0; + for(unsigned int chan = 0; chan < 4; ++chan) { + if (GET_SWZ(inst->I.SrcReg[src].Swizzle, chan) != RC_SWIZZLE_UNUSED) + usemask |= 1 << chan; + } + + c->SwizzleCaps->Split(inst->I.SrcReg[src], usemask, &split); + + for(unsigned int phase = 0; phase < split.NumPhases; ++phase) { + struct rc_instruction * mov = rc_insert_new_instruction(c, inst->Prev); + unsigned int phase_refmask; + unsigned int masked_negate; + + mov->I.Opcode = RC_OPCODE_MOV; + mov->I.DstReg.File = RC_FILE_TEMPORARY; + mov->I.DstReg.Index = tempreg; + mov->I.DstReg.WriteMask = split.Phase[phase]; + mov->I.SrcReg[0] = inst->I.SrcReg[src]; + + phase_refmask = 0; + for(unsigned int chan = 0; chan < 4; ++chan) { + if (!GET_BIT(split.Phase[phase], chan)) + SET_SWZ(mov->I.SrcReg[0].Swizzle, chan, RC_SWIZZLE_UNUSED); + else + phase_refmask |= 1 << GET_SWZ(mov->I.SrcReg[0].Swizzle, chan); + } + + phase_refmask &= RC_MASK_XYZW; + + masked_negate = split.Phase[phase] & mov->I.SrcReg[0].Negate; + if (masked_negate == 0) + mov->I.SrcReg[0].Negate = 0; + else if (masked_negate == split.Phase[phase]) + mov->I.SrcReg[0].Negate = RC_MASK_XYZW; + + if (oldref) { + mov->Dataflow.SrcReg[0] = rc_dataflow_create_ref(c, oldref->Vector, mov); + mov->Dataflow.SrcReg[0]->UseMask = phase_refmask; + } + + mov->Dataflow.DstReg = rc_dataflow_create_vector(c, RC_FILE_TEMPORARY, tempreg, mov); + mov->Dataflow.DstReg->ValidMask = split.Phase[phase]; + + if (vector) { + mov->Dataflow.DstRegPrev = rc_dataflow_create_ref(c, vector, mov); + mov->Dataflow.DstRegPrev->UseMask = vector->ValidMask; + mov->Dataflow.DstReg->ValidMask |= vector->ValidMask; + mov->Dataflow.DstRegAliased = 1; + } + + mov->Dataflow.DstReg->UseMask = mov->Dataflow.DstReg->ValidMask; + vector = mov->Dataflow.DstReg; + } + + if (oldref) + rc_dataflow_remove_ref(oldref); + inst->Dataflow.SrcReg[src] = rc_dataflow_create_ref(c, vector, inst); + inst->Dataflow.SrcReg[src]->UseMask = usemask; + + inst->I.SrcReg[src].File = RC_FILE_TEMPORARY; + inst->I.SrcReg[src].Index = tempreg; + inst->I.SrcReg[src].Swizzle = 0; + inst->I.SrcReg[src].Negate = RC_MASK_NONE; + inst->I.SrcReg[src].Abs = 0; + for(unsigned int chan = 0; chan < 4; ++chan) { + SET_SWZ(inst->I.SrcReg[src].Swizzle, chan, + GET_BIT(usemask, chan) ? chan : RC_SWIZZLE_UNUSED); + } +} + +void rc_dataflow_swizzles(struct radeon_compiler * c) +{ + struct rc_instruction * inst; + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); + unsigned int src; + + for(src = 0; src < opcode->NumSrcRegs; ++src) { + if (!c->SwizzleCaps->IsNative(inst->I.Opcode, inst->I.SrcReg[src])) + rewrite_source(c, inst, src); + } + } +} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_nqssadce.c b/src/mesa/drivers/dri/r300/compiler/radeon_nqssadce.c deleted file mode 100644 index 3e02ebee81f..00000000000 --- a/src/mesa/drivers/dri/r300/compiler/radeon_nqssadce.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2008 Nicolai Haehnle. - * - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. - * - */ - -/** - * @file - * - * "Not-quite SSA" and Dead-Code Elimination. - */ - -#include "radeon_nqssadce.h" - -#include "radeon_compiler.h" - - -/** - * Return the @ref register_state for the given register (or 0 for untracked - * registers, i.e. constants). - */ -static struct register_state *get_reg_state(struct nqssadce_state* s, rc_register_file file, unsigned int index) -{ - if (index >= RC_REGISTER_MAX_INDEX) - return 0; - - switch(file) { - case RC_FILE_TEMPORARY: return &s->Temps[index]; - case RC_FILE_OUTPUT: return &s->Outputs[index]; - case RC_FILE_ADDRESS: return &s->Address; - default: return 0; - } -} - - -static void track_used_srcreg(struct nqssadce_state* s, - int src, unsigned int sourced) -{ - struct rc_sub_instruction * inst = &s->IP->I; - int i; - unsigned int deswz_source = 0; - - for(i = 0; i < 4; ++i) { - if (GET_BIT(sourced, i)) { - unsigned int swz = GET_SWZ(inst->SrcReg[src].Swizzle, i); - deswz_source |= 1 << swz; - } else { - inst->SrcReg[src].Swizzle &= ~(7 << (3*i)); - inst->SrcReg[src].Swizzle |= RC_SWIZZLE_UNUSED << (3*i); - } - } - - if (!s->Descr->IsNativeSwizzle(inst->Opcode, inst->SrcReg[src])) { - struct rc_dst_register dstreg = inst->DstReg; - dstreg.File = RC_FILE_TEMPORARY; - dstreg.Index = rc_find_free_temporary(s->Compiler); - dstreg.WriteMask = sourced; - - s->Descr->BuildSwizzle(s, dstreg, inst->SrcReg[src]); - - inst->SrcReg[src].File = RC_FILE_TEMPORARY; - inst->SrcReg[src].Index = dstreg.Index; - inst->SrcReg[src].Swizzle = 0; - inst->SrcReg[src].Negate = RC_MASK_NONE; - inst->SrcReg[src].Abs = 0; - for(i = 0; i < 4; ++i) { - if (GET_BIT(sourced, i)) - inst->SrcReg[src].Swizzle |= i << (3*i); - else - inst->SrcReg[src].Swizzle |= RC_SWIZZLE_UNUSED << (3*i); - } - deswz_source = sourced; - } - - struct register_state *regstate; - - if (inst->SrcReg[src].RelAddr) { - regstate = get_reg_state(s, RC_FILE_ADDRESS, 0); - if (regstate) - regstate->Sourced |= RC_MASK_X; - } else { - regstate = get_reg_state(s, inst->SrcReg[src].File, inst->SrcReg[src].Index); - if (regstate) - regstate->Sourced |= deswz_source & 0xf; - } -} - -static void unalias_srcregs(struct rc_instruction *inst, unsigned int oldindex, unsigned int newindex) -{ - const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); - int i; - for(i = 0; i < opcode->NumSrcRegs; ++i) - if (inst->I.SrcReg[i].File == RC_FILE_TEMPORARY && inst->I.SrcReg[i].Index == oldindex) - inst->I.SrcReg[i].Index = newindex; -} - -static void unalias_temporary(struct nqssadce_state* s, unsigned int oldindex) -{ - unsigned int newindex = rc_find_free_temporary(s->Compiler); - struct rc_instruction * inst; - for(inst = s->Compiler->Program.Instructions.Next; inst != s->IP; inst = inst->Next) { - if (inst->I.DstReg.File == RC_FILE_TEMPORARY && inst->I.DstReg.Index == oldindex) - inst->I.DstReg.Index = newindex; - unalias_srcregs(inst, oldindex, newindex); - } - unalias_srcregs(s->IP, oldindex, newindex); -} - - -/** - * Handle one instruction. - */ -static void process_instruction(struct nqssadce_state* s) -{ - struct rc_sub_instruction *inst = &s->IP->I; - unsigned int WriteMask; - - if (inst->Opcode != RC_OPCODE_KIL) { - struct register_state *regstate = get_reg_state(s, inst->DstReg.File, inst->DstReg.Index); - if (!regstate) { - rc_error(s->Compiler, "NqssaDce: bad destination register (%i[%i])\n", - inst->DstReg.File, inst->DstReg.Index); - return; - } - - inst->DstReg.WriteMask &= regstate->Sourced; - regstate->Sourced &= ~inst->DstReg.WriteMask; - - if (inst->DstReg.WriteMask == 0) { - struct rc_instruction * inst_remove = s->IP; - s->IP = s->IP->Prev; - rc_remove_instruction(inst_remove); - return; - } - - if (inst->DstReg.File == RC_FILE_TEMPORARY && !regstate->Sourced) - unalias_temporary(s, inst->DstReg.Index); - } - - WriteMask = inst->DstReg.WriteMask; - - switch (inst->Opcode) { - case RC_OPCODE_ARL: - case RC_OPCODE_DDX: - case RC_OPCODE_DDY: - case RC_OPCODE_FRC: - case RC_OPCODE_MOV: - track_used_srcreg(s, 0, WriteMask); - break; - case RC_OPCODE_ADD: - case RC_OPCODE_MAX: - case RC_OPCODE_MIN: - case RC_OPCODE_MUL: - case RC_OPCODE_SGE: - case RC_OPCODE_SLT: - track_used_srcreg(s, 0, WriteMask); - track_used_srcreg(s, 1, WriteMask); - break; - case RC_OPCODE_CMP: - case RC_OPCODE_MAD: - track_used_srcreg(s, 0, WriteMask); - track_used_srcreg(s, 1, WriteMask); - track_used_srcreg(s, 2, WriteMask); - break; - case RC_OPCODE_COS: - case RC_OPCODE_EX2: - case RC_OPCODE_LG2: - case RC_OPCODE_RCP: - case RC_OPCODE_RSQ: - case RC_OPCODE_SIN: - track_used_srcreg(s, 0, 0x1); - break; - case RC_OPCODE_DP3: - track_used_srcreg(s, 0, 0x7); - track_used_srcreg(s, 1, 0x7); - break; - case RC_OPCODE_DP4: - track_used_srcreg(s, 0, 0xf); - track_used_srcreg(s, 1, 0xf); - break; - case RC_OPCODE_KIL: - case RC_OPCODE_TEX: - case RC_OPCODE_TXB: - case RC_OPCODE_TXP: - track_used_srcreg(s, 0, 0xf); - break; - case RC_OPCODE_DST: - track_used_srcreg(s, 0, 0x6); - track_used_srcreg(s, 1, 0xa); - break; - case RC_OPCODE_EXP: - case RC_OPCODE_LOG: - case RC_OPCODE_POW: - track_used_srcreg(s, 0, 0x3); - break; - case RC_OPCODE_LIT: - track_used_srcreg(s, 0, 0xb); - break; - default: - rc_error(s->Compiler, "NqssaDce: Unknown opcode %d\n", inst->Opcode); - return; - } - - s->IP = s->IP->Prev; -} - -void rc_calculate_inputs_outputs(struct radeon_compiler * c) -{ - struct rc_instruction *inst; - - c->Program.InputsRead = 0; - c->Program.OutputsWritten = 0; - - for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) - { - const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); - int i; - - for (i = 0; i < opcode->NumSrcRegs; ++i) { - if (inst->I.SrcReg[i].File == RC_FILE_INPUT) - c->Program.InputsRead |= 1 << inst->I.SrcReg[i].Index; - } - - if (opcode->HasDstReg) { - if (inst->I.DstReg.File == RC_FILE_OUTPUT) - c->Program.OutputsWritten |= 1 << inst->I.DstReg.Index; - } - } -} - -void radeonNqssaDce(struct radeon_compiler * c, struct radeon_nqssadce_descr* descr, void * data) -{ - struct nqssadce_state s; - - memset(&s, 0, sizeof(s)); - s.Compiler = c; - s.Descr = descr; - s.UserData = data; - s.Descr->Init(&s); - s.IP = c->Program.Instructions.Prev; - - while(s.IP != &c->Program.Instructions && !c->Error) - process_instruction(&s); - - rc_calculate_inputs_outputs(c); -} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_nqssadce.h b/src/mesa/drivers/dri/r300/compiler/radeon_nqssadce.h deleted file mode 100644 index a2aa1eb8ca3..00000000000 --- a/src/mesa/drivers/dri/r300/compiler/radeon_nqssadce.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2008 Nicolai Haehnle. - * - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 __RADEON_PROGRAM_NQSSADCE_H_ -#define __RADEON_PROGRAM_NQSSADCE_H_ - -#include "radeon_program.h" - -struct register_state { - /** - * Bitmask indicating which components of the register are sourced - * by later instructions. - */ - unsigned int Sourced : 4; -}; - -/** - * Maintain state such as which registers are used, which registers are - * read from, etc. - */ -struct nqssadce_state { - struct radeon_compiler *Compiler; - struct radeon_nqssadce_descr *Descr; - - /** - * All instructions after this instruction pointer have been dealt with. - */ - struct rc_instruction * IP; - - /** - * Which registers are read by subsequent instructions? - */ - struct register_state Temps[RC_REGISTER_MAX_INDEX]; - struct register_state Outputs[RC_REGISTER_MAX_INDEX]; - struct register_state Address; - - void * UserData; -}; - - -/** - * This structure contains a description of the hardware in-so-far as - * it is required for the NqSSA-DCE pass. - */ -struct radeon_nqssadce_descr { - /** - * Fill in which outputs - */ - void (*Init)(struct nqssadce_state *); - - /** - * Check whether the given swizzle, absolute and negate combination - * can be implemented natively by the hardware for this opcode. - * - * \return 1 if the swizzle is native for the given opcode - */ - int (*IsNativeSwizzle)(rc_opcode opcode, struct rc_src_register reg); - - /** - * Emit (at the current IP) the instruction MOV dst, src; - * The transformation will work recursively on the emitted instruction(s). - */ - void (*BuildSwizzle)(struct nqssadce_state*, struct rc_dst_register dst, struct rc_src_register src); -}; - -void radeonNqssaDce(struct radeon_compiler * c, struct radeon_nqssadce_descr* descr, void * data); - -#endif /* __RADEON_PROGRAM_NQSSADCE_H_ */ diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.c b/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.c index ffe2de1a873..b7200990c22 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.c @@ -40,13 +40,15 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .Opcode = RC_OPCODE_ABS, .Name = "ABS", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_ADD, .Name = "ADD", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_ARL, @@ -58,25 +60,29 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .Opcode = RC_OPCODE_CMP, .Name = "CMP", .NumSrcRegs = 3, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_COS, .Name = "COS", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsStandardScalar = 1 }, { .Opcode = RC_OPCODE_DDX, .Name = "DDX", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_DDY, .Name = "DDY", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_DP3, @@ -106,7 +112,8 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .Opcode = RC_OPCODE_EX2, .Name = "EX2", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsStandardScalar = 1 }, { .Opcode = RC_OPCODE_EXP, @@ -118,13 +125,15 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .Opcode = RC_OPCODE_FLR, .Name = "FLR", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_FRC, .Name = "FRC", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_KIL, @@ -135,7 +144,8 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .Opcode = RC_OPCODE_LG2, .Name = "LG2", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsStandardScalar = 1 }, { .Opcode = RC_OPCODE_LIT, @@ -153,55 +163,64 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .Opcode = RC_OPCODE_LRP, .Name = "LRP", .NumSrcRegs = 3, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_MAD, .Name = "MAD", .NumSrcRegs = 3, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_MAX, .Name = "MAX", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_MIN, .Name = "MIN", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_MOV, .Name = "MOV", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_MUL, .Name = "MUL", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_POW, .Name = "POW", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsStandardScalar = 1 }, { .Opcode = RC_OPCODE_RCP, .Name = "RCP", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsStandardScalar = 1 }, { .Opcode = RC_OPCODE_RSQ, .Name = "RSQ", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsStandardScalar = 1 }, { .Opcode = RC_OPCODE_SCS, @@ -213,61 +232,71 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .Opcode = RC_OPCODE_SEQ, .Name = "SEQ", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_SFL, .Name = "SFL", .NumSrcRegs = 0, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_SGE, .Name = "SGE", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_SGT, .Name = "SGT", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_SIN, .Name = "SIN", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsStandardScalar = 1 }, { .Opcode = RC_OPCODE_SLE, .Name = "SLE", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_SLT, .Name = "SLT", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_SNE, .Name = "SNE", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_SUB, .Name = "SUB", .NumSrcRegs = 2, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_SWZ, .Name = "SWZ", .NumSrcRegs = 1, - .HasDstReg = 1 + .HasDstReg = 1, + .IsComponentwise = 1 }, { .Opcode = RC_OPCODE_XPD, diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.h b/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.h index 4eb9be3e556..8e30bef1e3e 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.h +++ b/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.h @@ -187,6 +187,14 @@ struct rc_opcode_info { unsigned int NumSrcRegs:2; unsigned int HasDstReg:1; + + /** true if this is a vector instruction that operates on components in parallel + * without any cross-component interaction */ + unsigned int IsComponentwise:1; + + /** true if this instruction sources only its operands X components + * to compute one result which is smeared across all output channels */ + unsigned int IsStandardScalar:1; }; extern struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE]; diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program.c b/src/mesa/drivers/dri/r300/compiler/radeon_program.c index 0e0c1f68e64..b97c48084b4 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_program.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_program.c @@ -154,155 +154,7 @@ struct rc_instruction *rc_insert_new_instruction(struct radeon_compiler * c, str void rc_remove_instruction(struct rc_instruction * inst) { + rc_dataflow_remove_instruction(inst); inst->Prev->Next = inst->Next; inst->Next->Prev = inst->Prev; } - -static const char * textarget_to_string(rc_texture_target target) -{ - switch(target) { - case RC_TEXTURE_2D_ARRAY: return "2D_ARRAY"; - case RC_TEXTURE_1D_ARRAY: return "1D_ARRAY"; - case RC_TEXTURE_CUBE: return "CUBE"; - case RC_TEXTURE_3D: return "3D"; - case RC_TEXTURE_RECT: return "RECT"; - case RC_TEXTURE_2D: return "2D"; - case RC_TEXTURE_1D: return "1D"; - default: return "BAD_TEXTURE_TARGET"; - } -} - -static void rc_print_register(FILE * f, rc_register_file file, int index, unsigned int reladdr) -{ - if (file == RC_FILE_NONE) { - fprintf(f, "none"); - } else { - const char * filename; - switch(file) { - case RC_FILE_TEMPORARY: filename = "temp"; break; - case RC_FILE_INPUT: filename = "input"; break; - case RC_FILE_OUTPUT: filename = "output"; break; - case RC_FILE_ADDRESS: filename = "addr"; break; - case RC_FILE_CONSTANT: filename = "const"; break; - default: filename = "BAD FILE"; break; - } - fprintf(f, "%s[%i%s]", filename, index, reladdr ? " + addr[0]" : ""); - } -} - -static void rc_print_mask(FILE * f, unsigned int mask) -{ - if (mask & RC_MASK_X) fprintf(f, "x"); - if (mask & RC_MASK_Y) fprintf(f, "y"); - if (mask & RC_MASK_Z) fprintf(f, "z"); - if (mask & RC_MASK_W) fprintf(f, "w"); -} - -static void rc_print_dst_register(FILE * f, struct rc_dst_register dst) -{ - rc_print_register(f, dst.File, dst.Index, dst.RelAddr); - if (dst.WriteMask != RC_MASK_XYZW) { - fprintf(f, "."); - rc_print_mask(f, dst.WriteMask); - } -} - -static void rc_print_swizzle(FILE * f, unsigned int swizzle, unsigned int negate) -{ - unsigned int comp; - for(comp = 0; comp < 4; ++comp) { - rc_swizzle swz = GET_SWZ(swizzle, comp); - if (GET_BIT(negate, comp)) - fprintf(f, "-"); - switch(swz) { - case RC_SWIZZLE_X: fprintf(f, "x"); break; - case RC_SWIZZLE_Y: fprintf(f, "y"); break; - case RC_SWIZZLE_Z: fprintf(f, "z"); break; - case RC_SWIZZLE_W: fprintf(f, "w"); break; - case RC_SWIZZLE_ZERO: fprintf(f, "0"); break; - case RC_SWIZZLE_ONE: fprintf(f, "1"); break; - case RC_SWIZZLE_HALF: fprintf(f, "H"); break; - case RC_SWIZZLE_UNUSED: fprintf(f, "_"); break; - } - } -} - -static void rc_print_src_register(FILE * f, struct rc_src_register src) -{ - int trivial_negate = (src.Negate == RC_MASK_NONE || src.Negate == RC_MASK_XYZW); - - if (src.Negate == RC_MASK_XYZW) - fprintf(f, "-"); - if (src.Abs) - fprintf(f, "|"); - - rc_print_register(f, src.File, src.Index, src.RelAddr); - - if (src.Abs && !trivial_negate) - fprintf(f, "|"); - - if (src.Swizzle != RC_SWIZZLE_XYZW || !trivial_negate) { - fprintf(f, "."); - rc_print_swizzle(f, src.Swizzle, trivial_negate ? 0 : src.Negate); - } - - if (src.Abs && trivial_negate) - fprintf(f, "|"); -} - -static void rc_print_instruction(FILE * f, struct rc_instruction * inst) -{ - const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); - unsigned int reg; - - fprintf(f, "%s", opcode->Name); - - switch(inst->I.SaturateMode) { - case RC_SATURATE_NONE: break; - case RC_SATURATE_ZERO_ONE: fprintf(f, "_SAT"); break; - case RC_SATURATE_MINUS_PLUS_ONE: fprintf(f, "_SAT2"); break; - default: fprintf(f, "_BAD_SAT"); break; - } - - if (opcode->HasDstReg) { - fprintf(f, " "); - rc_print_dst_register(f, inst->I.DstReg); - if (opcode->NumSrcRegs) - fprintf(f, ","); - } - - for(reg = 0; reg < opcode->NumSrcRegs; ++reg) { - if (reg > 0) - fprintf(f, ","); - fprintf(f, " "); - rc_print_src_register(f, inst->I.SrcReg[reg]); - } - - if (opcode->HasTexture) { - fprintf(f, ", %s%s[%u]", - textarget_to_string(inst->I.TexSrcTarget), - inst->I.TexShadow ? "SHADOW" : "", - inst->I.TexSrcUnit); - } - - fprintf(f, ";\n"); -} - -/** - * Print program to stderr, default options. - */ -void rc_print_program(const struct rc_program *prog) -{ - unsigned int linenum = 0; - struct rc_instruction *inst; - - fprintf(stderr, "# Radeon Compiler Program\n"); - - for(inst = prog->Instructions.Next; inst != &prog->Instructions; inst = inst->Next) { - fprintf(stderr, "%3d: ", linenum); - - rc_print_instruction(stderr, inst); - - linenum++; - } -} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program.h b/src/mesa/drivers/dri/r300/compiler/radeon_program.h index a2ab757fec6..d38c9a420c6 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_program.h +++ b/src/mesa/drivers/dri/r300/compiler/radeon_program.h @@ -33,102 +33,11 @@ #include "radeon_opcodes.h" #include "radeon_code.h" +#include "radeon_program_constants.h" +#include "radeon_dataflow.h" struct radeon_compiler; -typedef enum { - RC_SATURATE_NONE = 0, - RC_SATURATE_ZERO_ONE, - RC_SATURATE_MINUS_PLUS_ONE -} rc_saturate_mode; - -typedef enum { - RC_TEXTURE_2D_ARRAY, - RC_TEXTURE_1D_ARRAY, - RC_TEXTURE_CUBE, - RC_TEXTURE_3D, - RC_TEXTURE_RECT, - RC_TEXTURE_2D, - RC_TEXTURE_1D -} rc_texture_target; - -typedef enum { - /** - * Used to indicate unused register descriptions and - * source register that use a constant swizzle. - */ - RC_FILE_NONE = 0, - RC_FILE_TEMPORARY, - - /** - * Input register. - * - * \note The compiler attaches no implicit semantics to input registers. - * Fragment/vertex program specific semantics must be defined explicitly - * using the appropriate compiler interfaces. - */ - RC_FILE_INPUT, - - /** - * Output register. - * - * \note The compiler attaches no implicit semantics to input registers. - * Fragment/vertex program specific semantics must be defined explicitly - * using the appropriate compiler interfaces. - */ - RC_FILE_OUTPUT, - RC_FILE_ADDRESS, - - /** - * Indicates a constant from the \ref rc_constant_list . - */ - RC_FILE_CONSTANT -} rc_register_file; - -#define RC_REGISTER_INDEX_BITS 10 -#define RC_REGISTER_MAX_INDEX (1 << RC_REGISTER_INDEX_BITS) - -typedef enum { - RC_SWIZZLE_X = 0, - RC_SWIZZLE_Y, - RC_SWIZZLE_Z, - RC_SWIZZLE_W, - RC_SWIZZLE_ZERO, - RC_SWIZZLE_ONE, - RC_SWIZZLE_HALF, - RC_SWIZZLE_UNUSED -} rc_swizzle; - -#define RC_MAKE_SWIZZLE(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9)) -#define RC_MAKE_SWIZZLE_SMEAR(a) RC_MAKE_SWIZZLE((a),(a),(a),(a)) -#define GET_SWZ(swz, idx) (((swz) >> ((idx)*3)) & 0x7) -#define GET_BIT(msk, idx) (((msk) >> (idx)) & 0x1) - -#define RC_SWIZZLE_XYZW RC_MAKE_SWIZZLE(RC_SWIZZLE_X, RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_W) -#define RC_SWIZZLE_XXXX RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_X) -#define RC_SWIZZLE_YYYY RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_Y) -#define RC_SWIZZLE_ZZZZ RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_Z) -#define RC_SWIZZLE_WWWW RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_W) -#define RC_SWIZZLE_0000 RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_ZERO) -#define RC_SWIZZLE_1111 RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_ONE) - -/** - * \name Bitmasks for components of vectors. - * - * Used for write masks, negation masks, etc. - */ -/*@{*/ -#define RC_MASK_NONE 0 -#define RC_MASK_X 1 -#define RC_MASK_Y 2 -#define RC_MASK_Z 4 -#define RC_MASK_W 8 -#define RC_MASK_XY (RC_MASK_X|RC_MASK_Y) -#define RC_MASK_XYZ (RC_MASK_X|RC_MASK_Y|RC_MASK_Z) -#define RC_MASK_XYW (RC_MASK_X|RC_MASK_Y|RC_MASK_W) -#define RC_MASK_XYZW (RC_MASK_X|RC_MASK_Y|RC_MASK_Z|RC_MASK_W) -/*@}*/ - struct rc_src_register { rc_register_file File:3; @@ -198,6 +107,15 @@ struct rc_instruction { struct rc_instruction * Next; struct rc_sub_instruction I; + + /** + * Dataflow annotations. + * + * These are not supplied by the caller of the compiler, + * but filled in during compilation stages that make use of + * dataflow analysis. + */ + struct rc_instruction_dataflow Dataflow; }; struct rc_program { @@ -292,6 +210,10 @@ struct rc_instruction *rc_alloc_instruction(struct radeon_compiler * c); struct rc_instruction *rc_insert_new_instruction(struct radeon_compiler * c, struct rc_instruction * after); void rc_remove_instruction(struct rc_instruction * inst); -void rc_print_program(const struct rc_program *prog); +enum { + RC_PRINT_DATAFLOW = 0x1 +}; + +void rc_print_program(const struct rc_program *prog, unsigned int flags); #endif diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_constants.h b/src/mesa/drivers/dri/r300/compiler/radeon_program_constants.h new file mode 100644 index 00000000000..69994f9880f --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_constants.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 RADEON_PROGRAM_CONSTANTS_H +#define RADEON_PROGRAM_CONSTANTS_H + +typedef enum { + RC_SATURATE_NONE = 0, + RC_SATURATE_ZERO_ONE, + RC_SATURATE_MINUS_PLUS_ONE +} rc_saturate_mode; + +typedef enum { + RC_TEXTURE_2D_ARRAY, + RC_TEXTURE_1D_ARRAY, + RC_TEXTURE_CUBE, + RC_TEXTURE_3D, + RC_TEXTURE_RECT, + RC_TEXTURE_2D, + RC_TEXTURE_1D +} rc_texture_target; + +typedef enum { + /** + * Used to indicate unused register descriptions and + * source register that use a constant swizzle. + */ + RC_FILE_NONE = 0, + RC_FILE_TEMPORARY, + + /** + * Input register. + * + * \note The compiler attaches no implicit semantics to input registers. + * Fragment/vertex program specific semantics must be defined explicitly + * using the appropriate compiler interfaces. + */ + RC_FILE_INPUT, + + /** + * Output register. + * + * \note The compiler attaches no implicit semantics to input registers. + * Fragment/vertex program specific semantics must be defined explicitly + * using the appropriate compiler interfaces. + */ + RC_FILE_OUTPUT, + RC_FILE_ADDRESS, + + /** + * Indicates a constant from the \ref rc_constant_list . + */ + RC_FILE_CONSTANT +} rc_register_file; + +#define RC_REGISTER_INDEX_BITS 10 +#define RC_REGISTER_MAX_INDEX (1 << RC_REGISTER_INDEX_BITS) + +typedef enum { + RC_SWIZZLE_X = 0, + RC_SWIZZLE_Y, + RC_SWIZZLE_Z, + RC_SWIZZLE_W, + RC_SWIZZLE_ZERO, + RC_SWIZZLE_ONE, + RC_SWIZZLE_HALF, + RC_SWIZZLE_UNUSED +} rc_swizzle; + +#define RC_MAKE_SWIZZLE(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9)) +#define RC_MAKE_SWIZZLE_SMEAR(a) RC_MAKE_SWIZZLE((a),(a),(a),(a)) +#define GET_SWZ(swz, idx) (((swz) >> ((idx)*3)) & 0x7) +#define GET_BIT(msk, idx) (((msk) >> (idx)) & 0x1) +#define SET_SWZ(swz, idx, newv) \ + do { \ + (swz) = ((swz) & ~(7 << ((idx)*3))) | ((newv) << ((idx)*3)); \ + } while(0) + +#define RC_SWIZZLE_XYZW RC_MAKE_SWIZZLE(RC_SWIZZLE_X, RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_W) +#define RC_SWIZZLE_XXXX RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_X) +#define RC_SWIZZLE_YYYY RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_Y) +#define RC_SWIZZLE_ZZZZ RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_Z) +#define RC_SWIZZLE_WWWW RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_W) +#define RC_SWIZZLE_0000 RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_ZERO) +#define RC_SWIZZLE_1111 RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_ONE) + +/** + * \name Bitmasks for components of vectors. + * + * Used for write masks, negation masks, etc. + */ +/*@{*/ +#define RC_MASK_NONE 0 +#define RC_MASK_X 1 +#define RC_MASK_Y 2 +#define RC_MASK_Z 4 +#define RC_MASK_W 8 +#define RC_MASK_XY (RC_MASK_X|RC_MASK_Y) +#define RC_MASK_XYZ (RC_MASK_X|RC_MASK_Y|RC_MASK_Z) +#define RC_MASK_XYW (RC_MASK_X|RC_MASK_Y|RC_MASK_W) +#define RC_MASK_XYZW (RC_MASK_X|RC_MASK_Y|RC_MASK_Z|RC_MASK_W) +/*@}*/ + +#endif /* RADEON_PROGRAM_CONSTANTS_H */ diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_print.c b/src/mesa/drivers/dri/r300/compiler/radeon_program_print.c new file mode 100644 index 00000000000..38060ea3adf --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_print.c @@ -0,0 +1,214 @@ +/* + * Copyright 2009 Nicolai Hähnle + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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 "radeon_program.h" + +#include + +static void print_comment(FILE * f) +{ + fprintf(f, " # "); +} + +static const char * textarget_to_string(rc_texture_target target) +{ + switch(target) { + case RC_TEXTURE_2D_ARRAY: return "2D_ARRAY"; + case RC_TEXTURE_1D_ARRAY: return "1D_ARRAY"; + case RC_TEXTURE_CUBE: return "CUBE"; + case RC_TEXTURE_3D: return "3D"; + case RC_TEXTURE_RECT: return "RECT"; + case RC_TEXTURE_2D: return "2D"; + case RC_TEXTURE_1D: return "1D"; + default: return "BAD_TEXTURE_TARGET"; + } +} + +static void rc_print_register(FILE * f, rc_register_file file, int index, unsigned int reladdr) +{ + if (file == RC_FILE_NONE) { + fprintf(f, "none"); + } else { + const char * filename; + switch(file) { + case RC_FILE_TEMPORARY: filename = "temp"; break; + case RC_FILE_INPUT: filename = "input"; break; + case RC_FILE_OUTPUT: filename = "output"; break; + case RC_FILE_ADDRESS: filename = "addr"; break; + case RC_FILE_CONSTANT: filename = "const"; break; + default: filename = "BAD FILE"; break; + } + fprintf(f, "%s[%i%s]", filename, index, reladdr ? " + addr[0]" : ""); + } +} + +static void rc_print_mask(FILE * f, unsigned int mask) +{ + if (mask & RC_MASK_X) fprintf(f, "x"); + if (mask & RC_MASK_Y) fprintf(f, "y"); + if (mask & RC_MASK_Z) fprintf(f, "z"); + if (mask & RC_MASK_W) fprintf(f, "w"); +} + +static void rc_print_dst_register(FILE * f, struct rc_dst_register dst) +{ + rc_print_register(f, dst.File, dst.Index, dst.RelAddr); + if (dst.WriteMask != RC_MASK_XYZW) { + fprintf(f, "."); + rc_print_mask(f, dst.WriteMask); + } +} + +static void rc_print_swizzle(FILE * f, unsigned int swizzle, unsigned int negate) +{ + unsigned int comp; + for(comp = 0; comp < 4; ++comp) { + rc_swizzle swz = GET_SWZ(swizzle, comp); + if (GET_BIT(negate, comp)) + fprintf(f, "-"); + switch(swz) { + case RC_SWIZZLE_X: fprintf(f, "x"); break; + case RC_SWIZZLE_Y: fprintf(f, "y"); break; + case RC_SWIZZLE_Z: fprintf(f, "z"); break; + case RC_SWIZZLE_W: fprintf(f, "w"); break; + case RC_SWIZZLE_ZERO: fprintf(f, "0"); break; + case RC_SWIZZLE_ONE: fprintf(f, "1"); break; + case RC_SWIZZLE_HALF: fprintf(f, "H"); break; + case RC_SWIZZLE_UNUSED: fprintf(f, "_"); break; + } + } +} + +static void rc_print_src_register(FILE * f, struct rc_src_register src) +{ + int trivial_negate = (src.Negate == RC_MASK_NONE || src.Negate == RC_MASK_XYZW); + + if (src.Negate == RC_MASK_XYZW) + fprintf(f, "-"); + if (src.Abs) + fprintf(f, "|"); + + rc_print_register(f, src.File, src.Index, src.RelAddr); + + if (src.Abs && !trivial_negate) + fprintf(f, "|"); + + if (src.Swizzle != RC_SWIZZLE_XYZW || !trivial_negate) { + fprintf(f, "."); + rc_print_swizzle(f, src.Swizzle, trivial_negate ? 0 : src.Negate); + } + + if (src.Abs && trivial_negate) + fprintf(f, "|"); +} + +static void rc_print_ref(FILE * f, struct rc_dataflow_ref * ref) +{ + fprintf(f, "ref(%p", ref->Vector); + + if (ref->UseMask != RC_MASK_XYZW) { + fprintf(f, "."); + rc_print_mask(f, ref->UseMask); + } + + fprintf(f, ")"); +} + +static void rc_print_instruction(FILE * f, unsigned int flags, struct rc_instruction * inst) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode); + unsigned int reg; + + fprintf(f, "%s", opcode->Name); + + switch(inst->I.SaturateMode) { + case RC_SATURATE_NONE: break; + case RC_SATURATE_ZERO_ONE: fprintf(f, "_SAT"); break; + case RC_SATURATE_MINUS_PLUS_ONE: fprintf(f, "_SAT2"); break; + default: fprintf(f, "_BAD_SAT"); break; + } + + if (opcode->HasDstReg) { + fprintf(f, " "); + rc_print_dst_register(f, inst->I.DstReg); + if (opcode->NumSrcRegs) + fprintf(f, ","); + } + + for(reg = 0; reg < opcode->NumSrcRegs; ++reg) { + if (reg > 0) + fprintf(f, ","); + fprintf(f, " "); + rc_print_src_register(f, inst->I.SrcReg[reg]); + } + + if (opcode->HasTexture) { + fprintf(f, ", %s%s[%u]", + textarget_to_string(inst->I.TexSrcTarget), + inst->I.TexShadow ? "SHADOW" : "", + inst->I.TexSrcUnit); + } + + fprintf(f, ";\n"); + + if (flags & RC_PRINT_DATAFLOW) { + print_comment(f); + + fprintf(f, "Dst = %p", inst->Dataflow.DstReg); + if (inst->Dataflow.DstRegAliased) + fprintf(f, " aliased"); + if (inst->Dataflow.DstRegPrev) { + fprintf(f, " from "); + rc_print_ref(f, inst->Dataflow.DstRegPrev); + } + + for(reg = 0; reg < opcode->NumSrcRegs; ++reg) { + fprintf(f, ", "); + if (inst->Dataflow.SrcReg[reg]) + rc_print_ref(f, inst->Dataflow.SrcReg[reg]); + else + fprintf(f, ""); + } + + fprintf(f, "\n"); + } +} + +/** + * Print program to stderr, default options. + */ +void rc_print_program(const struct rc_program *prog, unsigned int flags) +{ + unsigned int linenum = 0; + struct rc_instruction *inst; + + fprintf(stderr, "# Radeon Compiler Program%s\n", + flags & RC_PRINT_DATAFLOW ? " (with dataflow annotations)" : ""); + + for(inst = prog->Instructions.Next; inst != &prog->Instructions; inst = inst->Next) { + fprintf(stderr, "%3d: ", linenum); + + rc_print_instruction(stderr, flags, inst); + + linenum++; + } +} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_swizzle.h b/src/mesa/drivers/dri/r300/compiler/radeon_swizzle.h new file mode 100644 index 00000000000..c81d5f7a5e9 --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_swizzle.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 RADEON_SWIZZLE_H +#define RADEON_SWIZZLE_H + +#include "radeon_program.h" + +struct rc_swizzle_split { + unsigned char NumPhases; + unsigned char Phase[4]; +}; + +/** + * Describe the swizzling capability of target hardware. + */ +struct rc_swizzle_caps { + /** + * Check whether the given swizzle, absolute and negate combination + * can be implemented natively by the hardware for this opcode. + * + * \return 1 if the swizzle is native for the given opcode + */ + int (*IsNative)(rc_opcode opcode, struct rc_src_register reg); + + /** + * Determine how to split access to the masked channels of the + * given source register to obtain ALU-native swizzles. + */ + void (*Split)(struct rc_src_register reg, unsigned int mask, struct rc_swizzle_split * split); +}; + +#endif /* RADEON_SWIZZLE_H */ diff --git a/src/mesa/drivers/dri/r300/r300_vertprog.c b/src/mesa/drivers/dri/r300/r300_vertprog.c index be21268ba5e..b7d5429dc57 100644 --- a/src/mesa/drivers/dri/r300/r300_vertprog.c +++ b/src/mesa/drivers/dri/r300/r300_vertprog.c @@ -41,7 +41,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tnl/tnl.h" #include "compiler/radeon_compiler.h" -#include "compiler/radeon_nqssadce.h" #include "radeon_mesa_to_rc.h" #include "r300_context.h" #include "r300_state.h" -- cgit v1.2.3