1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2011 Tom Stellard <tstellar@gmail.com> 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining 7bf215546Sopenharmony_ci * a copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial 16bf215546Sopenharmony_ci * portions of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 22bf215546Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23bf215546Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24bf215546Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include <stdio.h> 29bf215546Sopenharmony_ci#include <stdlib.h> 30bf215546Sopenharmony_ci#include "radeon_variable.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "memory_pool.h" 33bf215546Sopenharmony_ci#include "radeon_compiler_util.h" 34bf215546Sopenharmony_ci#include "radeon_dataflow.h" 35bf215546Sopenharmony_ci#include "radeon_list.h" 36bf215546Sopenharmony_ci#include "radeon_opcodes.h" 37bf215546Sopenharmony_ci#include "radeon_program.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci/** 40bf215546Sopenharmony_ci * Rewrite the index and writemask for the destination register of var 41bf215546Sopenharmony_ci * and its friends to new_index and new_writemask. This function also takes 42bf215546Sopenharmony_ci * care of rewriting the swizzles for the sources of var. 43bf215546Sopenharmony_ci */ 44bf215546Sopenharmony_civoid rc_variable_change_dst( 45bf215546Sopenharmony_ci struct rc_variable * var, 46bf215546Sopenharmony_ci unsigned int new_index, 47bf215546Sopenharmony_ci unsigned int new_writemask) 48bf215546Sopenharmony_ci{ 49bf215546Sopenharmony_ci struct rc_variable * var_ptr; 50bf215546Sopenharmony_ci struct rc_list * readers; 51bf215546Sopenharmony_ci unsigned int old_mask = rc_variable_writemask_sum(var); 52bf215546Sopenharmony_ci unsigned int conversion_swizzle = 53bf215546Sopenharmony_ci rc_make_conversion_swizzle(old_mask, new_writemask); 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci for (var_ptr = var; var_ptr; var_ptr = var_ptr->Friend) { 56bf215546Sopenharmony_ci if (var_ptr->Inst->Type == RC_INSTRUCTION_NORMAL) { 57bf215546Sopenharmony_ci rc_normal_rewrite_writemask(var_ptr->Inst, 58bf215546Sopenharmony_ci conversion_swizzle); 59bf215546Sopenharmony_ci var_ptr->Inst->U.I.DstReg.Index = new_index; 60bf215546Sopenharmony_ci } else { 61bf215546Sopenharmony_ci struct rc_pair_sub_instruction * sub; 62bf215546Sopenharmony_ci if (var_ptr->Dst.WriteMask == RC_MASK_W) { 63bf215546Sopenharmony_ci assert(new_writemask & RC_MASK_W); 64bf215546Sopenharmony_ci sub = &var_ptr->Inst->U.P.Alpha; 65bf215546Sopenharmony_ci } else { 66bf215546Sopenharmony_ci sub = &var_ptr->Inst->U.P.RGB; 67bf215546Sopenharmony_ci rc_pair_rewrite_writemask(sub, 68bf215546Sopenharmony_ci conversion_swizzle); 69bf215546Sopenharmony_ci } 70bf215546Sopenharmony_ci sub->DestIndex = new_index; 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci } 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci readers = rc_variable_readers_union(var); 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci for ( ; readers; readers = readers->Next) { 77bf215546Sopenharmony_ci struct rc_reader * reader = readers->Item; 78bf215546Sopenharmony_ci if (reader->Inst->Type == RC_INSTRUCTION_NORMAL) { 79bf215546Sopenharmony_ci reader->U.I.Src->Index = new_index; 80bf215546Sopenharmony_ci reader->U.I.Src->Swizzle = rc_rewrite_swizzle( 81bf215546Sopenharmony_ci reader->U.I.Src->Swizzle, conversion_swizzle); 82bf215546Sopenharmony_ci } else { 83bf215546Sopenharmony_ci struct rc_pair_instruction * pair_inst = 84bf215546Sopenharmony_ci &reader->Inst->U.P; 85bf215546Sopenharmony_ci unsigned int src_type = rc_source_type_swz( 86bf215546Sopenharmony_ci reader->U.P.Arg->Swizzle); 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci int src_index = reader->U.P.Arg->Source; 89bf215546Sopenharmony_ci if (src_index == RC_PAIR_PRESUB_SRC) { 90bf215546Sopenharmony_ci src_index = rc_pair_get_src_index( 91bf215546Sopenharmony_ci pair_inst, reader->U.P.Src); 92bf215546Sopenharmony_ci } 93bf215546Sopenharmony_ci rc_pair_remove_src(reader->Inst, src_type, 94bf215546Sopenharmony_ci src_index); 95bf215546Sopenharmony_ci /* Reuse the source index of the source that 96bf215546Sopenharmony_ci * was just deleted and set its register 97bf215546Sopenharmony_ci * index. We can't use rc_pair_alloc_source 98bf215546Sopenharmony_ci * for this because it might return a source 99bf215546Sopenharmony_ci * index that is already being used. */ 100bf215546Sopenharmony_ci if (src_type & RC_SOURCE_RGB) { 101bf215546Sopenharmony_ci pair_inst->RGB.Src[src_index] 102bf215546Sopenharmony_ci .Used = 1; 103bf215546Sopenharmony_ci pair_inst->RGB.Src[src_index] 104bf215546Sopenharmony_ci .Index = new_index; 105bf215546Sopenharmony_ci pair_inst->RGB.Src[src_index] 106bf215546Sopenharmony_ci .File = RC_FILE_TEMPORARY; 107bf215546Sopenharmony_ci } 108bf215546Sopenharmony_ci if (src_type & RC_SOURCE_ALPHA) { 109bf215546Sopenharmony_ci pair_inst->Alpha.Src[src_index] 110bf215546Sopenharmony_ci .Used = 1; 111bf215546Sopenharmony_ci pair_inst->Alpha.Src[src_index] 112bf215546Sopenharmony_ci .Index = new_index; 113bf215546Sopenharmony_ci pair_inst->Alpha.Src[src_index] 114bf215546Sopenharmony_ci .File = RC_FILE_TEMPORARY; 115bf215546Sopenharmony_ci } 116bf215546Sopenharmony_ci reader->U.P.Arg->Swizzle = rc_rewrite_swizzle( 117bf215546Sopenharmony_ci reader->U.P.Arg->Swizzle, conversion_swizzle); 118bf215546Sopenharmony_ci if (reader->U.P.Arg->Source != RC_PAIR_PRESUB_SRC) { 119bf215546Sopenharmony_ci reader->U.P.Arg->Source = src_index; 120bf215546Sopenharmony_ci } 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci } 123bf215546Sopenharmony_ci} 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci/** 126bf215546Sopenharmony_ci * Compute the live intervals for var and its friends. 127bf215546Sopenharmony_ci */ 128bf215546Sopenharmony_civoid rc_variable_compute_live_intervals(struct rc_variable * var) 129bf215546Sopenharmony_ci{ 130bf215546Sopenharmony_ci while(var) { 131bf215546Sopenharmony_ci unsigned int i; 132bf215546Sopenharmony_ci unsigned int start = var->Inst->IP; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci for (i = 0; i < var->ReaderCount; i++) { 135bf215546Sopenharmony_ci unsigned int chan; 136bf215546Sopenharmony_ci unsigned int chan_start = start; 137bf215546Sopenharmony_ci unsigned int chan_end = var->Readers[i].Inst->IP; 138bf215546Sopenharmony_ci unsigned int mask = var->Readers[i].WriteMask; 139bf215546Sopenharmony_ci struct rc_instruction * inst; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci /* Extend the live interval of T0 to the start of the 142bf215546Sopenharmony_ci * loop for sequences like: 143bf215546Sopenharmony_ci * BGNLOOP 144bf215546Sopenharmony_ci * read T0 145bf215546Sopenharmony_ci * ... 146bf215546Sopenharmony_ci * write T0 147bf215546Sopenharmony_ci * ENDLOOP 148bf215546Sopenharmony_ci */ 149bf215546Sopenharmony_ci if (var->Readers[i].Inst->IP < start) { 150bf215546Sopenharmony_ci struct rc_instruction * bgnloop = 151bf215546Sopenharmony_ci rc_match_endloop(var->Readers[i].Inst); 152bf215546Sopenharmony_ci chan_start = bgnloop->IP; 153bf215546Sopenharmony_ci } 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci /* Extend the live interval of T0 to the start of the 156bf215546Sopenharmony_ci * loop in case there is a BRK instruction in the loop 157bf215546Sopenharmony_ci * (we don't actually check for a BRK instruction we 158bf215546Sopenharmony_ci * assume there is one somewhere in the loop, which 159bf215546Sopenharmony_ci * there usually is) for sequences like: 160bf215546Sopenharmony_ci * BGNLOOP 161bf215546Sopenharmony_ci * ... 162bf215546Sopenharmony_ci * conditional BRK 163bf215546Sopenharmony_ci * ... 164bf215546Sopenharmony_ci * write T0 165bf215546Sopenharmony_ci * ENDLOOP 166bf215546Sopenharmony_ci * read T0 167bf215546Sopenharmony_ci *************************************************** 168bf215546Sopenharmony_ci * Extend the live interval of T0 to the end of the 169bf215546Sopenharmony_ci * loop for sequences like: 170bf215546Sopenharmony_ci * write T0 171bf215546Sopenharmony_ci * BGNLOOP 172bf215546Sopenharmony_ci * ... 173bf215546Sopenharmony_ci * read T0 174bf215546Sopenharmony_ci * ENDLOOP 175bf215546Sopenharmony_ci */ 176bf215546Sopenharmony_ci for (inst = var->Inst; inst != var->Readers[i].Inst; 177bf215546Sopenharmony_ci inst = inst->Next) { 178bf215546Sopenharmony_ci rc_opcode op = rc_get_flow_control_inst(inst); 179bf215546Sopenharmony_ci if (op == RC_OPCODE_ENDLOOP) { 180bf215546Sopenharmony_ci struct rc_instruction * bgnloop = 181bf215546Sopenharmony_ci rc_match_endloop(inst); 182bf215546Sopenharmony_ci if (bgnloop->IP < chan_start) { 183bf215546Sopenharmony_ci chan_start = bgnloop->IP; 184bf215546Sopenharmony_ci } 185bf215546Sopenharmony_ci } else if (op == RC_OPCODE_BGNLOOP) { 186bf215546Sopenharmony_ci struct rc_instruction * endloop = 187bf215546Sopenharmony_ci rc_match_bgnloop(inst); 188bf215546Sopenharmony_ci if (endloop->IP > chan_end) { 189bf215546Sopenharmony_ci chan_end = endloop->IP; 190bf215546Sopenharmony_ci } 191bf215546Sopenharmony_ci } 192bf215546Sopenharmony_ci } 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci for (chan = 0; chan < 4; chan++) { 195bf215546Sopenharmony_ci if ((mask >> chan) & 0x1) { 196bf215546Sopenharmony_ci if (!var->Live[chan].Used 197bf215546Sopenharmony_ci || chan_start < var->Live[chan].Start) { 198bf215546Sopenharmony_ci var->Live[chan].Start = 199bf215546Sopenharmony_ci chan_start; 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci if (!var->Live[chan].Used 202bf215546Sopenharmony_ci || chan_end > var->Live[chan].End) { 203bf215546Sopenharmony_ci var->Live[chan].End = chan_end; 204bf215546Sopenharmony_ci } 205bf215546Sopenharmony_ci var->Live[chan].Used = 1; 206bf215546Sopenharmony_ci } 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci } 209bf215546Sopenharmony_ci var = var->Friend; 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci} 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci/** 214bf215546Sopenharmony_ci * @return 1 if a and b share a reader 215bf215546Sopenharmony_ci * @return 0 if they do not 216bf215546Sopenharmony_ci */ 217bf215546Sopenharmony_cistatic unsigned int readers_intersect( 218bf215546Sopenharmony_ci struct rc_variable * a, 219bf215546Sopenharmony_ci struct rc_variable * b) 220bf215546Sopenharmony_ci{ 221bf215546Sopenharmony_ci unsigned int a_index, b_index; 222bf215546Sopenharmony_ci for (a_index = 0; a_index < a->ReaderCount; a_index++) { 223bf215546Sopenharmony_ci struct rc_reader reader_a = a->Readers[a_index]; 224bf215546Sopenharmony_ci for (b_index = 0; b_index < b->ReaderCount; b_index++) { 225bf215546Sopenharmony_ci struct rc_reader reader_b = b->Readers[b_index]; 226bf215546Sopenharmony_ci if (reader_a.Inst->Type == RC_INSTRUCTION_NORMAL 227bf215546Sopenharmony_ci && reader_b.Inst->Type == RC_INSTRUCTION_NORMAL 228bf215546Sopenharmony_ci && reader_a.U.I.Src == reader_b.U.I.Src) { 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci return 1; 231bf215546Sopenharmony_ci } 232bf215546Sopenharmony_ci if (reader_a.Inst->Type == RC_INSTRUCTION_PAIR 233bf215546Sopenharmony_ci && reader_b.Inst->Type == RC_INSTRUCTION_PAIR 234bf215546Sopenharmony_ci && reader_a.U.P.Src == reader_b.U.P.Src) { 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci return 1; 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci } 239bf215546Sopenharmony_ci } 240bf215546Sopenharmony_ci return 0; 241bf215546Sopenharmony_ci} 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_civoid rc_variable_add_friend( 244bf215546Sopenharmony_ci struct rc_variable * var, 245bf215546Sopenharmony_ci struct rc_variable * friend) 246bf215546Sopenharmony_ci{ 247bf215546Sopenharmony_ci assert(var->Dst.Index == friend->Dst.Index); 248bf215546Sopenharmony_ci while(var->Friend) { 249bf215546Sopenharmony_ci var = var->Friend; 250bf215546Sopenharmony_ci } 251bf215546Sopenharmony_ci var->Friend = friend; 252bf215546Sopenharmony_ci} 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_cistruct rc_variable * rc_variable( 255bf215546Sopenharmony_ci struct radeon_compiler * c, 256bf215546Sopenharmony_ci unsigned int DstFile, 257bf215546Sopenharmony_ci unsigned int DstIndex, 258bf215546Sopenharmony_ci unsigned int DstWriteMask, 259bf215546Sopenharmony_ci struct rc_reader_data * reader_data) 260bf215546Sopenharmony_ci{ 261bf215546Sopenharmony_ci struct rc_variable * new = 262bf215546Sopenharmony_ci memory_pool_malloc(&c->Pool, sizeof(struct rc_variable)); 263bf215546Sopenharmony_ci memset(new, 0, sizeof(struct rc_variable)); 264bf215546Sopenharmony_ci new->C = c; 265bf215546Sopenharmony_ci new->Dst.File = DstFile; 266bf215546Sopenharmony_ci new->Dst.Index = DstIndex; 267bf215546Sopenharmony_ci new->Dst.WriteMask = DstWriteMask; 268bf215546Sopenharmony_ci if (reader_data) { 269bf215546Sopenharmony_ci new->Inst = reader_data->Writer; 270bf215546Sopenharmony_ci new->ReaderCount = reader_data->ReaderCount; 271bf215546Sopenharmony_ci new->Readers = reader_data->Readers; 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci return new; 274bf215546Sopenharmony_ci} 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_cistatic void get_variable_helper( 277bf215546Sopenharmony_ci struct rc_list ** variable_list, 278bf215546Sopenharmony_ci struct rc_variable * variable) 279bf215546Sopenharmony_ci{ 280bf215546Sopenharmony_ci struct rc_list * list_ptr; 281bf215546Sopenharmony_ci for (list_ptr = *variable_list; list_ptr; list_ptr = list_ptr->Next) { 282bf215546Sopenharmony_ci struct rc_variable * var; 283bf215546Sopenharmony_ci for (var = list_ptr->Item; var; var = var->Friend) { 284bf215546Sopenharmony_ci if (readers_intersect(var, variable)) { 285bf215546Sopenharmony_ci rc_variable_add_friend(var, variable); 286bf215546Sopenharmony_ci return; 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci } 289bf215546Sopenharmony_ci } 290bf215546Sopenharmony_ci rc_list_add(variable_list, rc_list(&variable->C->Pool, variable)); 291bf215546Sopenharmony_ci} 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_cistatic void get_variable_pair_helper( 294bf215546Sopenharmony_ci struct rc_list ** variable_list, 295bf215546Sopenharmony_ci struct radeon_compiler * c, 296bf215546Sopenharmony_ci struct rc_instruction * inst, 297bf215546Sopenharmony_ci struct rc_pair_sub_instruction * sub_inst) 298bf215546Sopenharmony_ci{ 299bf215546Sopenharmony_ci struct rc_reader_data reader_data; 300bf215546Sopenharmony_ci struct rc_variable * new_var; 301bf215546Sopenharmony_ci rc_register_file file; 302bf215546Sopenharmony_ci unsigned int writemask; 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci if (sub_inst->Opcode == RC_OPCODE_NOP) { 305bf215546Sopenharmony_ci return; 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci memset(&reader_data, 0, sizeof(struct rc_reader_data)); 308bf215546Sopenharmony_ci rc_get_readers_sub(c, inst, sub_inst, &reader_data, NULL, NULL, NULL); 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci if (reader_data.ReaderCount == 0) { 311bf215546Sopenharmony_ci return; 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci if (sub_inst->WriteMask) { 315bf215546Sopenharmony_ci file = RC_FILE_TEMPORARY; 316bf215546Sopenharmony_ci writemask = sub_inst->WriteMask; 317bf215546Sopenharmony_ci } else if (sub_inst->OutputWriteMask) { 318bf215546Sopenharmony_ci file = RC_FILE_OUTPUT; 319bf215546Sopenharmony_ci writemask = sub_inst->OutputWriteMask; 320bf215546Sopenharmony_ci } else { 321bf215546Sopenharmony_ci writemask = 0; 322bf215546Sopenharmony_ci file = RC_FILE_NONE; 323bf215546Sopenharmony_ci } 324bf215546Sopenharmony_ci new_var = rc_variable(c, file, sub_inst->DestIndex, writemask, 325bf215546Sopenharmony_ci &reader_data); 326bf215546Sopenharmony_ci get_variable_helper(variable_list, new_var); 327bf215546Sopenharmony_ci} 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci/** 330bf215546Sopenharmony_ci * Compare function for sorting variable pointers by the lowest instruction 331bf215546Sopenharmony_ci * IP from it and its friends. 332bf215546Sopenharmony_ci */ 333bf215546Sopenharmony_cistatic int cmpfunc_variable_by_ip (const void * a, const void * b) { 334bf215546Sopenharmony_ci struct rc_variable * var_a = *(struct rc_variable **)a; 335bf215546Sopenharmony_ci struct rc_variable * var_b = *(struct rc_variable **)b; 336bf215546Sopenharmony_ci unsigned int min_ip_a = var_a->Inst->IP; 337bf215546Sopenharmony_ci unsigned int min_ip_b = var_b->Inst->IP; 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci /* Find the minimal IP of a variable and its friends */ 340bf215546Sopenharmony_ci while (var_a->Friend) { 341bf215546Sopenharmony_ci var_a = var_a->Friend; 342bf215546Sopenharmony_ci if (var_a->Inst->IP < min_ip_a) 343bf215546Sopenharmony_ci min_ip_a = var_a->Inst->IP; 344bf215546Sopenharmony_ci } 345bf215546Sopenharmony_ci while (var_b->Friend) { 346bf215546Sopenharmony_ci var_b = var_b->Friend; 347bf215546Sopenharmony_ci if (var_b->Inst->IP < min_ip_b) 348bf215546Sopenharmony_ci min_ip_b = var_b->Inst->IP; 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci return (int)min_ip_a - (int)min_ip_b; 352bf215546Sopenharmony_ci} 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci/** 355bf215546Sopenharmony_ci * Generate a list of variables used by the shader program. Each instruction 356bf215546Sopenharmony_ci * that writes to a register is considered a variable. The struct rc_variable 357bf215546Sopenharmony_ci * data structure includes a list of readers and is essentially a 358bf215546Sopenharmony_ci * definition-use chain. Any two variables that share a reader are considered 359bf215546Sopenharmony_ci * "friends" and they are linked together via the Friend attribute. 360bf215546Sopenharmony_ci */ 361bf215546Sopenharmony_cistruct rc_list * rc_get_variables(struct radeon_compiler * c) 362bf215546Sopenharmony_ci{ 363bf215546Sopenharmony_ci struct rc_instruction * inst; 364bf215546Sopenharmony_ci struct rc_list * variable_list = NULL; 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_ci /* We search for the variables in two loops in order to get it right in 367bf215546Sopenharmony_ci * the following specific case 368bf215546Sopenharmony_ci * 369bf215546Sopenharmony_ci * IF aluresult.x___; 370bf215546Sopenharmony_ci * ... 371bf215546Sopenharmony_ci * MAD temp[0].xyz, src0.000, src0.111, src0.000 372bf215546Sopenharmony_ci * MAD temp[0].w, src0.0, src0.1, src0.0 373bf215546Sopenharmony_ci * ELSE; 374bf215546Sopenharmony_ci * ... 375bf215546Sopenharmony_ci * TXB temp[0], temp[1].xy_w, 2D[0] SEM_WAIT SEM_ACQUIRE; 376bf215546Sopenharmony_ci * ENDIF; 377bf215546Sopenharmony_ci * src0.xyz = input[0], src0.w = input[0], src1.xyz = temp[0], src1.w = temp[0] SEM_WAIT 378bf215546Sopenharmony_ci * MAD temp[1].xyz, src0.xyz, src1.xyz, src0.000 379bf215546Sopenharmony_ci * MAD temp[1].w, src0.w, src1.w, src0.0 380bf215546Sopenharmony_ci * 381bf215546Sopenharmony_ci * If we go just in one loop, we will first create two variables for the 382bf215546Sopenharmony_ci * temp[0].xyz and temp[0].w. This happens because they don't share a reader 383bf215546Sopenharmony_ci * as the src1.xyz and src1.w of the instruction where the value is used are 384bf215546Sopenharmony_ci * in theory independent. They are not because the same register is written 385bf215546Sopenharmony_ci * also by the texture instruction in the other branch and TEX can't write xyz 386bf215546Sopenharmony_ci * and w separatelly. 387bf215546Sopenharmony_ci * 388bf215546Sopenharmony_ci * Therefore first search for RC_INSTRUCTION_NORMAL to create variables from 389bf215546Sopenharmony_ci * the texture instruction and than the pair instructions will be properly 390bf215546Sopenharmony_ci * marked as friends. So we will end with only one variable here as we should. 391bf215546Sopenharmony_ci * 392bf215546Sopenharmony_ci * This doesn't matter before the pair translation, because everything is 393bf215546Sopenharmony_ci * RC_INSTRUCTION_NORMAL. 394bf215546Sopenharmony_ci */ 395bf215546Sopenharmony_ci for (inst = c->Program.Instructions.Next; 396bf215546Sopenharmony_ci inst != &c->Program.Instructions; 397bf215546Sopenharmony_ci inst = inst->Next) { 398bf215546Sopenharmony_ci if (inst->Type == RC_INSTRUCTION_NORMAL) { 399bf215546Sopenharmony_ci struct rc_reader_data reader_data; 400bf215546Sopenharmony_ci struct rc_variable * new_var; 401bf215546Sopenharmony_ci memset(&reader_data, 0, sizeof(reader_data)); 402bf215546Sopenharmony_ci rc_get_readers(c, inst, &reader_data, NULL, NULL, NULL); 403bf215546Sopenharmony_ci if (reader_data.ReaderCount == 0) { 404bf215546Sopenharmony_ci continue; 405bf215546Sopenharmony_ci } 406bf215546Sopenharmony_ci new_var = rc_variable(c, inst->U.I.DstReg.File, 407bf215546Sopenharmony_ci inst->U.I.DstReg.Index, 408bf215546Sopenharmony_ci inst->U.I.DstReg.WriteMask, &reader_data); 409bf215546Sopenharmony_ci get_variable_helper(&variable_list, new_var); 410bf215546Sopenharmony_ci } 411bf215546Sopenharmony_ci } 412bf215546Sopenharmony_ci 413bf215546Sopenharmony_ci bool needs_sorting = false; 414bf215546Sopenharmony_ci for (inst = c->Program.Instructions.Next; 415bf215546Sopenharmony_ci inst != &c->Program.Instructions; 416bf215546Sopenharmony_ci inst = inst->Next) { 417bf215546Sopenharmony_ci if (inst->Type != RC_INSTRUCTION_NORMAL) { 418bf215546Sopenharmony_ci needs_sorting = true; 419bf215546Sopenharmony_ci get_variable_pair_helper(&variable_list, c, inst, 420bf215546Sopenharmony_ci &inst->U.P.RGB); 421bf215546Sopenharmony_ci get_variable_pair_helper(&variable_list, c, inst, 422bf215546Sopenharmony_ci &inst->U.P.Alpha); 423bf215546Sopenharmony_ci } 424bf215546Sopenharmony_ci } 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci if (variable_list && needs_sorting) { 427bf215546Sopenharmony_ci unsigned int count = rc_list_count(variable_list); 428bf215546Sopenharmony_ci struct rc_variable **variables = memory_pool_malloc(&c->Pool, 429bf215546Sopenharmony_ci sizeof(struct rc_variable *) * count); 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci struct rc_list * current = variable_list; 432bf215546Sopenharmony_ci for(unsigned int i = 0; current; i++, current = current->Next) { 433bf215546Sopenharmony_ci struct rc_variable * var = current->Item; 434bf215546Sopenharmony_ci variables[i] = var; 435bf215546Sopenharmony_ci } 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci qsort(variables, count, sizeof(struct rc_variable *), cmpfunc_variable_by_ip); 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci current = variable_list; 440bf215546Sopenharmony_ci for(unsigned int i = 0; current; i++, current = current->Next) { 441bf215546Sopenharmony_ci current->Item = variables[i]; 442bf215546Sopenharmony_ci } 443bf215546Sopenharmony_ci } 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci return variable_list; 446bf215546Sopenharmony_ci} 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci/** 449bf215546Sopenharmony_ci * @return The bitwise or of the writemasks of a variable and all of its 450bf215546Sopenharmony_ci * friends. 451bf215546Sopenharmony_ci */ 452bf215546Sopenharmony_ciunsigned int rc_variable_writemask_sum(struct rc_variable * var) 453bf215546Sopenharmony_ci{ 454bf215546Sopenharmony_ci unsigned int writemask = 0; 455bf215546Sopenharmony_ci while(var) { 456bf215546Sopenharmony_ci writemask |= var->Dst.WriteMask; 457bf215546Sopenharmony_ci var = var->Friend; 458bf215546Sopenharmony_ci } 459bf215546Sopenharmony_ci return writemask; 460bf215546Sopenharmony_ci} 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci/* 463bf215546Sopenharmony_ci * @return A list of readers for a variable and its friends. Readers 464bf215546Sopenharmony_ci * that read from two different variable friends are only included once in 465bf215546Sopenharmony_ci * this list. 466bf215546Sopenharmony_ci */ 467bf215546Sopenharmony_cistruct rc_list * rc_variable_readers_union(struct rc_variable * var) 468bf215546Sopenharmony_ci{ 469bf215546Sopenharmony_ci struct rc_list * list = NULL; 470bf215546Sopenharmony_ci while (var) { 471bf215546Sopenharmony_ci unsigned int i; 472bf215546Sopenharmony_ci for (i = 0; i < var->ReaderCount; i++) { 473bf215546Sopenharmony_ci struct rc_list * temp; 474bf215546Sopenharmony_ci struct rc_reader * a = &var->Readers[i]; 475bf215546Sopenharmony_ci unsigned int match = 0; 476bf215546Sopenharmony_ci for (temp = list; temp; temp = temp->Next) { 477bf215546Sopenharmony_ci struct rc_reader * b = temp->Item; 478bf215546Sopenharmony_ci if (a->Inst->Type != b->Inst->Type) { 479bf215546Sopenharmony_ci continue; 480bf215546Sopenharmony_ci } 481bf215546Sopenharmony_ci if (a->Inst->Type == RC_INSTRUCTION_NORMAL) { 482bf215546Sopenharmony_ci if (a->U.I.Src == b->U.I.Src) { 483bf215546Sopenharmony_ci match = 1; 484bf215546Sopenharmony_ci break; 485bf215546Sopenharmony_ci } 486bf215546Sopenharmony_ci } 487bf215546Sopenharmony_ci if (a->Inst->Type == RC_INSTRUCTION_PAIR) { 488bf215546Sopenharmony_ci if (a->U.P.Arg == b->U.P.Arg 489bf215546Sopenharmony_ci && a->U.P.Src == b->U.P.Src) { 490bf215546Sopenharmony_ci match = 1; 491bf215546Sopenharmony_ci break; 492bf215546Sopenharmony_ci } 493bf215546Sopenharmony_ci } 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci if (match) { 496bf215546Sopenharmony_ci continue; 497bf215546Sopenharmony_ci } 498bf215546Sopenharmony_ci rc_list_add(&list, rc_list(&var->C->Pool, a)); 499bf215546Sopenharmony_ci } 500bf215546Sopenharmony_ci var = var->Friend; 501bf215546Sopenharmony_ci } 502bf215546Sopenharmony_ci return list; 503bf215546Sopenharmony_ci} 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_cistatic unsigned int reader_equals_src( 506bf215546Sopenharmony_ci struct rc_reader reader, 507bf215546Sopenharmony_ci unsigned int src_type, 508bf215546Sopenharmony_ci void * src) 509bf215546Sopenharmony_ci{ 510bf215546Sopenharmony_ci if (reader.Inst->Type != src_type) { 511bf215546Sopenharmony_ci return 0; 512bf215546Sopenharmony_ci } 513bf215546Sopenharmony_ci if (src_type == RC_INSTRUCTION_NORMAL) { 514bf215546Sopenharmony_ci return reader.U.I.Src == src; 515bf215546Sopenharmony_ci } else { 516bf215546Sopenharmony_ci return reader.U.P.Src == src; 517bf215546Sopenharmony_ci } 518bf215546Sopenharmony_ci} 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_cistatic unsigned int variable_writes_src( 521bf215546Sopenharmony_ci struct rc_variable * var, 522bf215546Sopenharmony_ci unsigned int src_type, 523bf215546Sopenharmony_ci void * src) 524bf215546Sopenharmony_ci{ 525bf215546Sopenharmony_ci unsigned int i; 526bf215546Sopenharmony_ci for (i = 0; i < var->ReaderCount; i++) { 527bf215546Sopenharmony_ci if (reader_equals_src(var->Readers[i], src_type, src)) { 528bf215546Sopenharmony_ci return 1; 529bf215546Sopenharmony_ci } 530bf215546Sopenharmony_ci } 531bf215546Sopenharmony_ci return 0; 532bf215546Sopenharmony_ci} 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_ci 535bf215546Sopenharmony_cistruct rc_list * rc_variable_list_get_writers( 536bf215546Sopenharmony_ci struct rc_list * var_list, 537bf215546Sopenharmony_ci unsigned int src_type, 538bf215546Sopenharmony_ci void * src) 539bf215546Sopenharmony_ci{ 540bf215546Sopenharmony_ci struct rc_list * list_ptr; 541bf215546Sopenharmony_ci struct rc_list * writer_list = NULL; 542bf215546Sopenharmony_ci for (list_ptr = var_list; list_ptr; list_ptr = list_ptr->Next) { 543bf215546Sopenharmony_ci struct rc_variable * var = list_ptr->Item; 544bf215546Sopenharmony_ci if (variable_writes_src(var, src_type, src)) { 545bf215546Sopenharmony_ci struct rc_variable * friend; 546bf215546Sopenharmony_ci rc_list_add(&writer_list, rc_list(&var->C->Pool, var)); 547bf215546Sopenharmony_ci for (friend = var->Friend; friend; 548bf215546Sopenharmony_ci friend = friend->Friend) { 549bf215546Sopenharmony_ci if (variable_writes_src(friend, src_type, src)) { 550bf215546Sopenharmony_ci rc_list_add(&writer_list, 551bf215546Sopenharmony_ci rc_list(&var->C->Pool, friend)); 552bf215546Sopenharmony_ci } 553bf215546Sopenharmony_ci } 554bf215546Sopenharmony_ci /* Once we have identified the variable and its 555bf215546Sopenharmony_ci * friends that write this source, we can stop 556bf215546Sopenharmony_ci * stop searching, because we know none of the 557bf215546Sopenharmony_ci * other variables in the list will write this source. 558bf215546Sopenharmony_ci * If they did they would be friends of var. 559bf215546Sopenharmony_ci */ 560bf215546Sopenharmony_ci break; 561bf215546Sopenharmony_ci } 562bf215546Sopenharmony_ci } 563bf215546Sopenharmony_ci return writer_list; 564bf215546Sopenharmony_ci} 565bf215546Sopenharmony_ci 566bf215546Sopenharmony_cistruct rc_list * rc_variable_list_get_writers_one_reader( 567bf215546Sopenharmony_ci struct rc_list * var_list, 568bf215546Sopenharmony_ci unsigned int src_type, 569bf215546Sopenharmony_ci void * src) 570bf215546Sopenharmony_ci{ 571bf215546Sopenharmony_ci struct rc_list * writer_list = 572bf215546Sopenharmony_ci rc_variable_list_get_writers(var_list, src_type, src); 573bf215546Sopenharmony_ci struct rc_list * reader_list = 574bf215546Sopenharmony_ci rc_variable_readers_union(writer_list->Item); 575bf215546Sopenharmony_ci if (rc_list_count(reader_list) > 1) { 576bf215546Sopenharmony_ci return NULL; 577bf215546Sopenharmony_ci } else { 578bf215546Sopenharmony_ci return writer_list; 579bf215546Sopenharmony_ci } 580bf215546Sopenharmony_ci} 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_civoid rc_variable_print(struct rc_variable * var) 583bf215546Sopenharmony_ci{ 584bf215546Sopenharmony_ci unsigned int i; 585bf215546Sopenharmony_ci while (var) { 586bf215546Sopenharmony_ci fprintf(stderr, "%u: TEMP[%u].%u: ", 587bf215546Sopenharmony_ci var->Inst->IP, var->Dst.Index, var->Dst.WriteMask); 588bf215546Sopenharmony_ci for (i = 0; i < 4; i++) { 589bf215546Sopenharmony_ci fprintf(stderr, "chan %u: start=%u end=%u ", i, 590bf215546Sopenharmony_ci var->Live[i].Start, var->Live[i].End); 591bf215546Sopenharmony_ci } 592bf215546Sopenharmony_ci fprintf(stderr, "%u readers\n", var->ReaderCount); 593bf215546Sopenharmony_ci if (var->Friend) { 594bf215546Sopenharmony_ci fprintf(stderr, "Friend: \n\t"); 595bf215546Sopenharmony_ci } 596bf215546Sopenharmony_ci var = var->Friend; 597bf215546Sopenharmony_ci } 598bf215546Sopenharmony_ci} 599