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