"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/gallium/drivers/r300/compiler/radeon_compiler.c" (16 Sep 2020, 15406 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "radeon_compiler.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
    3  *
    4  * Permission is hereby granted, free of charge, to any person obtaining a
    5  * copy of this software and associated documentation files (the "Software"),
    6  * to deal in the Software without restriction, including without limitation
    7  * on the rights to use, copy, modify, merge, publish, distribute, sub
    8  * license, and/or sell copies of the Software, and to permit persons to whom
    9  * the Software is furnished to do so, subject to the following conditions:
   10  *
   11  * The above copyright notice and this permission notice (including the next
   12  * paragraph) shall be included in all copies or substantial portions of the
   13  * Software.
   14  *
   15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
   18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
   19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
   20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
   21  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
   22 
   23 #include "radeon_compiler.h"
   24 
   25 #include <stdarg.h>
   26 #include <stdio.h>
   27 #include <stdlib.h>
   28 
   29 #include "radeon_dataflow.h"
   30 #include "radeon_program.h"
   31 #include "radeon_program_pair.h"
   32 #include "radeon_regalloc.h"
   33 #include "radeon_compiler_util.h"
   34 
   35 
   36 void rc_init(struct radeon_compiler * c, const struct rc_regalloc_state *rs)
   37 {
   38     memset(c, 0, sizeof(*c));
   39 
   40     memory_pool_init(&c->Pool);
   41     c->Program.Instructions.Prev = &c->Program.Instructions;
   42     c->Program.Instructions.Next = &c->Program.Instructions;
   43     c->Program.Instructions.U.I.Opcode = RC_OPCODE_ILLEGAL_OPCODE;
   44     c->regalloc_state = rs;
   45 }
   46 
   47 void rc_destroy(struct radeon_compiler * c)
   48 {
   49     rc_constants_destroy(&c->Program.Constants);
   50     memory_pool_destroy(&c->Pool);
   51     free(c->ErrorMsg);
   52 }
   53 
   54 void rc_debug(struct radeon_compiler * c, const char * fmt, ...)
   55 {
   56     va_list ap;
   57 
   58     if (!(c->Debug & RC_DBG_LOG))
   59         return;
   60 
   61     va_start(ap, fmt);
   62     vfprintf(stderr, fmt, ap);
   63     va_end(ap);
   64 }
   65 
   66 void rc_error(struct radeon_compiler * c, const char * fmt, ...)
   67 {
   68     va_list ap;
   69 
   70     c->Error = 1;
   71 
   72     if (!c->ErrorMsg) {
   73         /* Only remember the first error */
   74         char buf[1024];
   75         int written;
   76 
   77         va_start(ap, fmt);
   78         written = vsnprintf(buf, sizeof(buf), fmt, ap);
   79         va_end(ap);
   80 
   81         if (written < sizeof(buf)) {
   82             c->ErrorMsg = strdup(buf);
   83         } else {
   84             c->ErrorMsg = malloc(written + 1);
   85 
   86             va_start(ap, fmt);
   87             vsnprintf(c->ErrorMsg, written + 1, fmt, ap);
   88             va_end(ap);
   89         }
   90     }
   91 
   92     if (c->Debug & RC_DBG_LOG) {
   93         fprintf(stderr, "r300compiler error: ");
   94 
   95         va_start(ap, fmt);
   96         vfprintf(stderr, fmt, ap);
   97         va_end(ap);
   98     }
   99 }
  100 
  101 int rc_if_fail_helper(struct radeon_compiler * c, const char * file, int line, const char * assertion)
  102 {
  103     rc_error(c, "ICE at %s:%i: assertion failed: %s\n", file, line, assertion);
  104     return 1;
  105 }
  106 
  107 /**
  108  * Recompute c->Program.InputsRead and c->Program.OutputsWritten
  109  * based on which inputs and outputs are actually referenced
  110  * in program instructions.
  111  */
  112 void rc_calculate_inputs_outputs(struct radeon_compiler * c)
  113 {
  114     struct rc_instruction *inst;
  115 
  116     c->Program.InputsRead = 0;
  117     c->Program.OutputsWritten = 0;
  118 
  119     for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next)
  120     {
  121         const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
  122         int i;
  123 
  124         for (i = 0; i < opcode->NumSrcRegs; ++i) {
  125             if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT)
  126                 c->Program.InputsRead |= 1 << inst->U.I.SrcReg[i].Index;
  127         }
  128 
  129         if (opcode->HasDstReg) {
  130             if (inst->U.I.DstReg.File == RC_FILE_OUTPUT)
  131                 c->Program.OutputsWritten |= 1 << inst->U.I.DstReg.Index;
  132         }
  133     }
  134 }
  135 
  136 /**
  137  * Rewrite the program such that everything that source the given input
  138  * register will source new_input instead.
  139  */
  140 void rc_move_input(struct radeon_compiler * c, unsigned input, struct rc_src_register new_input)
  141 {
  142     struct rc_instruction * inst;
  143 
  144     c->Program.InputsRead &= ~(1 << input);
  145 
  146     for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
  147         const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
  148         unsigned i;
  149 
  150         for(i = 0; i < opcode->NumSrcRegs; ++i) {
  151             if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT && inst->U.I.SrcReg[i].Index == input) {
  152                 inst->U.I.SrcReg[i].File = new_input.File;
  153                 inst->U.I.SrcReg[i].Index = new_input.Index;
  154                 inst->U.I.SrcReg[i].Swizzle = combine_swizzles(new_input.Swizzle, inst->U.I.SrcReg[i].Swizzle);
  155                 if (!inst->U.I.SrcReg[i].Abs) {
  156                     inst->U.I.SrcReg[i].Negate ^= new_input.Negate;
  157                     inst->U.I.SrcReg[i].Abs = new_input.Abs;
  158                 }
  159 
  160                 c->Program.InputsRead |= 1 << new_input.Index;
  161             }
  162         }
  163     }
  164 }
  165 
  166 
  167 /**
  168  * Rewrite the program such that everything that writes into the given
  169  * output register will instead write to new_output. The new_output
  170  * writemask is honoured.
  171  */
  172 void rc_move_output(struct radeon_compiler * c, unsigned output, unsigned new_output, unsigned writemask)
  173 {
  174     struct rc_instruction * inst;
  175 
  176     c->Program.OutputsWritten &= ~(1 << output);
  177 
  178     for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
  179         const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
  180 
  181         if (opcode->HasDstReg) {
  182             if (inst->U.I.DstReg.File == RC_FILE_OUTPUT && inst->U.I.DstReg.Index == output) {
  183                 inst->U.I.DstReg.Index = new_output;
  184                 inst->U.I.DstReg.WriteMask &= writemask;
  185 
  186                 c->Program.OutputsWritten |= 1 << new_output;
  187             }
  188         }
  189     }
  190 }
  191 
  192 
  193 /**
  194  * Rewrite the program such that a given output is duplicated.
  195  */
  196 void rc_copy_output(struct radeon_compiler * c, unsigned output, unsigned dup_output)
  197 {
  198     unsigned tempreg = rc_find_free_temporary(c);
  199     struct rc_instruction * inst;
  200 
  201     for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
  202         const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
  203 
  204         if (opcode->HasDstReg) {
  205             if (inst->U.I.DstReg.File == RC_FILE_OUTPUT && inst->U.I.DstReg.Index == output) {
  206                 inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
  207                 inst->U.I.DstReg.Index = tempreg;
  208             }
  209         }
  210     }
  211 
  212     inst = rc_insert_new_instruction(c, c->Program.Instructions.Prev);
  213     inst->U.I.Opcode = RC_OPCODE_MOV;
  214     inst->U.I.DstReg.File = RC_FILE_OUTPUT;
  215     inst->U.I.DstReg.Index = output;
  216 
  217     inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  218     inst->U.I.SrcReg[0].Index = tempreg;
  219     inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
  220 
  221     inst = rc_insert_new_instruction(c, c->Program.Instructions.Prev);
  222     inst->U.I.Opcode = RC_OPCODE_MOV;
  223     inst->U.I.DstReg.File = RC_FILE_OUTPUT;
  224     inst->U.I.DstReg.Index = dup_output;
  225 
  226     inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  227     inst->U.I.SrcReg[0].Index = tempreg;
  228     inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
  229 
  230     c->Program.OutputsWritten |= 1 << dup_output;
  231 }
  232 
  233 
  234 /**
  235  * Introduce standard code fragment to deal with fragment.position.
  236  */
  237 void rc_transform_fragment_wpos(struct radeon_compiler * c, unsigned wpos, unsigned new_input,
  238                                 int full_vtransform)
  239 {
  240     unsigned tempregi = rc_find_free_temporary(c);
  241     struct rc_instruction * inst_rcp;
  242     struct rc_instruction * inst_mul;
  243     struct rc_instruction * inst_mad;
  244     struct rc_instruction * inst;
  245 
  246     c->Program.InputsRead &= ~(1 << wpos);
  247     c->Program.InputsRead |= 1 << new_input;
  248 
  249     /* perspective divide */
  250     inst_rcp = rc_insert_new_instruction(c, &c->Program.Instructions);
  251     inst_rcp->U.I.Opcode = RC_OPCODE_RCP;
  252 
  253     inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY;
  254     inst_rcp->U.I.DstReg.Index = tempregi;
  255     inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W;
  256 
  257     inst_rcp->U.I.SrcReg[0].File = RC_FILE_INPUT;
  258     inst_rcp->U.I.SrcReg[0].Index = new_input;
  259     inst_rcp->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_WWWW;
  260 
  261     inst_mul = rc_insert_new_instruction(c, inst_rcp);
  262     inst_mul->U.I.Opcode = RC_OPCODE_MUL;
  263 
  264     inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
  265     inst_mul->U.I.DstReg.Index = tempregi;
  266     inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  267 
  268     inst_mul->U.I.SrcReg[0].File = RC_FILE_INPUT;
  269     inst_mul->U.I.SrcReg[0].Index = new_input;
  270 
  271     inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
  272     inst_mul->U.I.SrcReg[1].Index = tempregi;
  273     inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW;
  274 
  275     /* viewport transformation */
  276     inst_mad = rc_insert_new_instruction(c, inst_mul);
  277     inst_mad->U.I.Opcode = RC_OPCODE_MAD;
  278 
  279     inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
  280     inst_mad->U.I.DstReg.Index = tempregi;
  281     inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  282 
  283     inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  284     inst_mad->U.I.SrcReg[0].Index = tempregi;
  285     inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
  286 
  287     inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
  288     inst_mad->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0;
  289 
  290     inst_mad->U.I.SrcReg[2].File = RC_FILE_CONSTANT;
  291     inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_XYZ0;
  292 
  293     if (full_vtransform) {
  294         inst_mad->U.I.SrcReg[1].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_VIEWPORT_SCALE, 0);
  295         inst_mad->U.I.SrcReg[2].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_VIEWPORT_OFFSET, 0);
  296     } else {
  297         inst_mad->U.I.SrcReg[1].Index =
  298         inst_mad->U.I.SrcReg[2].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_WINDOW_DIMENSION, 0);
  299     }
  300 
  301     for (inst = inst_mad->Next; inst != &c->Program.Instructions; inst = inst->Next) {
  302         const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
  303         unsigned i;
  304 
  305         for(i = 0; i < opcode->NumSrcRegs; i++) {
  306             if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT &&
  307                 inst->U.I.SrcReg[i].Index == wpos) {
  308                 inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY;
  309                 inst->U.I.SrcReg[i].Index = tempregi;
  310             }
  311         }
  312     }
  313 }
  314 
  315 
  316 /**
  317  * The FACE input in hardware contains 1 if it's a back face, 0 otherwise.
  318  * Gallium and OpenGL define it the other way around.
  319  *
  320  * So let's just negate FACE at the beginning of the shader and rewrite the rest
  321  * of the shader to read from the newly allocated temporary.
  322  */
  323 void rc_transform_fragment_face(struct radeon_compiler *c, unsigned face)
  324 {
  325     unsigned tempregi = rc_find_free_temporary(c);
  326     struct rc_instruction *inst_add;
  327     struct rc_instruction *inst;
  328 
  329     /* perspective divide */
  330     inst_add = rc_insert_new_instruction(c, &c->Program.Instructions);
  331     inst_add->U.I.Opcode = RC_OPCODE_ADD;
  332 
  333     inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY;
  334     inst_add->U.I.DstReg.Index = tempregi;
  335     inst_add->U.I.DstReg.WriteMask = RC_MASK_X;
  336 
  337     inst_add->U.I.SrcReg[0].File = RC_FILE_NONE;
  338     inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111;
  339 
  340     inst_add->U.I.SrcReg[1].File = RC_FILE_INPUT;
  341     inst_add->U.I.SrcReg[1].Index = face;
  342     inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XXXX;
  343     inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZW;
  344 
  345     for (inst = inst_add->Next; inst != &c->Program.Instructions; inst = inst->Next) {
  346         const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
  347         unsigned i;
  348 
  349         for(i = 0; i < opcode->NumSrcRegs; i++) {
  350             if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT &&
  351                 inst->U.I.SrcReg[i].Index == face) {
  352                 inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY;
  353                 inst->U.I.SrcReg[i].Index = tempregi;
  354             }
  355         }
  356     }
  357 }
  358 
  359 static void reg_count_callback(void * userdata, struct rc_instruction * inst,
  360         rc_register_file file, unsigned int index, unsigned int mask)
  361 {
  362     struct rc_program_stats *s = userdata;
  363     if (file == RC_FILE_TEMPORARY)
  364         (int)index > s->num_temp_regs ? s->num_temp_regs = index : 0;
  365     if (file == RC_FILE_INLINE)
  366         s->num_inline_literals++;
  367 }
  368 
  369 void rc_get_stats(struct radeon_compiler *c, struct rc_program_stats *s)
  370 {
  371     struct rc_instruction * tmp;
  372     memset(s, 0, sizeof(*s));
  373 
  374     for(tmp = c->Program.Instructions.Next; tmp != &c->Program.Instructions;
  375                             tmp = tmp->Next){
  376         const struct rc_opcode_info * info;
  377         rc_for_all_reads_mask(tmp, reg_count_callback, s);
  378         if (tmp->Type == RC_INSTRUCTION_NORMAL) {
  379             info = rc_get_opcode_info(tmp->U.I.Opcode);
  380             if (info->Opcode == RC_OPCODE_BEGIN_TEX)
  381                 continue;
  382             if (tmp->U.I.PreSub.Opcode != RC_PRESUB_NONE)
  383                 s->num_presub_ops++;
  384         } else {
  385             if (tmp->U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Used)
  386                 s->num_presub_ops++;
  387             if (tmp->U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Used)
  388                 s->num_presub_ops++;
  389             /* Assuming alpha will never be a flow control or
  390              * a tex instruction. */
  391             if (tmp->U.P.Alpha.Opcode != RC_OPCODE_NOP)
  392                 s->num_alpha_insts++;
  393             if (tmp->U.P.RGB.Opcode != RC_OPCODE_NOP)
  394                 s->num_rgb_insts++;
  395             if (tmp->U.P.RGB.Omod != RC_OMOD_MUL_1 &&
  396                 tmp->U.P.RGB.Omod != RC_OMOD_DISABLE) {
  397                 s->num_omod_ops++;
  398             }
  399             if (tmp->U.P.Alpha.Omod != RC_OMOD_MUL_1 &&
  400                 tmp->U.P.Alpha.Omod != RC_OMOD_DISABLE) {
  401                 s->num_omod_ops++;
  402             }
  403             info = rc_get_opcode_info(tmp->U.P.RGB.Opcode);
  404         }
  405         if (info->IsFlowControl)
  406             s->num_fc_insts++;
  407         if (info->HasTexture)
  408             s->num_tex_insts++;
  409         s->num_insts++;
  410     }
  411     /* Increment here because the reg_count_callback store the max
  412      * temporary reg index in s->nun_temp_regs. */
  413     s->num_temp_regs++;
  414 }
  415 
  416 static void print_stats(struct radeon_compiler * c)
  417 {
  418     struct rc_program_stats s;
  419 
  420     if (c->initial_num_insts <= 5)
  421         return;
  422 
  423     rc_get_stats(c, &s);
  424 
  425     switch (c->type) {
  426     case RC_VERTEX_PROGRAM:
  427         fprintf(stderr,"~~~~~~~~~ VERTEX PROGRAM ~~~~~~~~\n"
  428                    "~%4u Instructions\n"
  429                    "~%4u Flow Control Instructions\n"
  430                    "~%4u Temporary Registers\n"
  431                    "~~~~~~~~~~~~~~ END ~~~~~~~~~~~~~~\n",
  432                    s.num_insts, s.num_fc_insts, s.num_temp_regs);
  433         break;
  434 
  435     case RC_FRAGMENT_PROGRAM:
  436         fprintf(stderr,"~~~~~~~~ FRAGMENT PROGRAM ~~~~~~~\n"
  437                    "~%4u Instructions\n"
  438                    "~%4u Vector Instructions (RGB)\n"
  439                    "~%4u Scalar Instructions (Alpha)\n"
  440                    "~%4u Flow Control Instructions\n"
  441                    "~%4u Texture Instructions\n"
  442                    "~%4u Presub Operations\n"
  443                    "~%4u OMOD Operations\n"
  444                    "~%4u Temporary Registers\n"
  445                    "~%4u Inline Literals\n"
  446                    "~~~~~~~~~~~~~~ END ~~~~~~~~~~~~~~\n",
  447                    s.num_insts, s.num_rgb_insts, s.num_alpha_insts,
  448                    s.num_fc_insts, s.num_tex_insts, s.num_presub_ops,
  449                    s.num_omod_ops, s.num_temp_regs, s.num_inline_literals);
  450         break;
  451     default:
  452         assert(0);
  453     }
  454 }
  455 
  456 static const char *shader_name[RC_NUM_PROGRAM_TYPES] = {
  457     "Vertex Program",
  458     "Fragment Program"
  459 };
  460 
  461 void rc_run_compiler_passes(struct radeon_compiler *c, struct radeon_compiler_pass *list)
  462 {
  463     for (unsigned i = 0; list[i].name; i++) {
  464         if (list[i].predicate) {
  465             list[i].run(c, list[i].user);
  466 
  467             if (c->Error)
  468                 return;
  469 
  470             if ((c->Debug & RC_DBG_LOG) && list[i].dump) {
  471                 fprintf(stderr, "%s: after '%s'\n", shader_name[c->type], list[i].name);
  472                 rc_print_program(&c->Program);
  473             }
  474         }
  475     }
  476 }
  477 
  478 /* Executes a list of compiler passes given in the parameter 'list'. */
  479 void rc_run_compiler(struct radeon_compiler *c, struct radeon_compiler_pass *list)
  480 {
  481     struct rc_program_stats s;
  482 
  483     rc_get_stats(c, &s);
  484     c->initial_num_insts = s.num_insts;
  485 
  486     if (c->Debug & RC_DBG_LOG) {
  487         fprintf(stderr, "%s: before compilation\n", shader_name[c->type]);
  488         rc_print_program(&c->Program);
  489     }
  490 
  491     rc_run_compiler_passes(c, list);
  492 
  493     if (c->Debug & RC_DBG_STATS)
  494         print_stats(c);
  495 }
  496 
  497 void rc_validate_final_shader(struct radeon_compiler *c, void *user)
  498 {
  499     /* Check the number of constants. */
  500     if (c->Program.Constants.Count > c->max_constants) {
  501         rc_error(c, "Too many constants. Max: %i, Got: %i\n",
  502              c->max_constants, c->Program.Constants.Count);
  503     }
  504 }