1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2009 Nicolai Haehnle. 3bf215546Sopenharmony_ci * Copyright 2010 Tom Stellard <tstellar@gmail.com> 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * All Rights Reserved. 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining 8bf215546Sopenharmony_ci * a copy of this software and associated documentation files (the 9bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 10bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 11bf215546Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to 12bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 13bf215546Sopenharmony_ci * the following conditions: 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 16bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial 17bf215546Sopenharmony_ci * portions of the Software. 18bf215546Sopenharmony_ci * 19bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22bf215546Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 23bf215546Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24bf215546Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25bf215546Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci */ 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "radeon_dataflow.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "radeon_compiler.h" 32bf215546Sopenharmony_ci#include "radeon_compiler_util.h" 33bf215546Sopenharmony_ci#include "radeon_program.h" 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_cistruct read_write_mask_data { 36bf215546Sopenharmony_ci void * UserData; 37bf215546Sopenharmony_ci rc_read_write_mask_fn Cb; 38bf215546Sopenharmony_ci}; 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_cistatic void reads_normal_callback( 41bf215546Sopenharmony_ci void * userdata, 42bf215546Sopenharmony_ci struct rc_instruction * fullinst, 43bf215546Sopenharmony_ci struct rc_src_register * src) 44bf215546Sopenharmony_ci{ 45bf215546Sopenharmony_ci struct read_write_mask_data * cb_data = userdata; 46bf215546Sopenharmony_ci unsigned int refmask = 0; 47bf215546Sopenharmony_ci unsigned int chan; 48bf215546Sopenharmony_ci for(chan = 0; chan < 4; chan++) { 49bf215546Sopenharmony_ci refmask |= 1 << GET_SWZ(src->Swizzle, chan); 50bf215546Sopenharmony_ci } 51bf215546Sopenharmony_ci refmask &= RC_MASK_XYZW; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci if (refmask) { 54bf215546Sopenharmony_ci cb_data->Cb(cb_data->UserData, fullinst, src->File, 55bf215546Sopenharmony_ci src->Index, refmask); 56bf215546Sopenharmony_ci } 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci if (refmask && src->RelAddr) { 59bf215546Sopenharmony_ci cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0, 60bf215546Sopenharmony_ci RC_MASK_X); 61bf215546Sopenharmony_ci } 62bf215546Sopenharmony_ci} 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_cistatic void pair_get_src_refmasks(unsigned int * refmasks, 65bf215546Sopenharmony_ci struct rc_pair_instruction * inst, 66bf215546Sopenharmony_ci unsigned int swz, unsigned int src) 67bf215546Sopenharmony_ci{ 68bf215546Sopenharmony_ci if (swz >= 4) 69bf215546Sopenharmony_ci return; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) { 72bf215546Sopenharmony_ci if(src == RC_PAIR_PRESUB_SRC) { 73bf215546Sopenharmony_ci unsigned int i; 74bf215546Sopenharmony_ci int srcp_regs = 75bf215546Sopenharmony_ci rc_presubtract_src_reg_count( 76bf215546Sopenharmony_ci inst->RGB.Src[src].Index); 77bf215546Sopenharmony_ci for(i = 0; i < srcp_regs; i++) { 78bf215546Sopenharmony_ci refmasks[i] |= 1 << swz; 79bf215546Sopenharmony_ci } 80bf215546Sopenharmony_ci } 81bf215546Sopenharmony_ci else { 82bf215546Sopenharmony_ci refmasks[src] |= 1 << swz; 83bf215546Sopenharmony_ci } 84bf215546Sopenharmony_ci } 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci if (swz == RC_SWIZZLE_W) { 87bf215546Sopenharmony_ci if (src == RC_PAIR_PRESUB_SRC) { 88bf215546Sopenharmony_ci unsigned int i; 89bf215546Sopenharmony_ci int srcp_regs = rc_presubtract_src_reg_count( 90bf215546Sopenharmony_ci inst->Alpha.Src[src].Index); 91bf215546Sopenharmony_ci for(i = 0; i < srcp_regs; i++) { 92bf215546Sopenharmony_ci refmasks[i] |= 1 << swz; 93bf215546Sopenharmony_ci } 94bf215546Sopenharmony_ci } 95bf215546Sopenharmony_ci else { 96bf215546Sopenharmony_ci refmasks[src] |= 1 << swz; 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci } 99bf215546Sopenharmony_ci} 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_cistatic void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) 102bf215546Sopenharmony_ci{ 103bf215546Sopenharmony_ci struct rc_pair_instruction * inst = &fullinst->U.P; 104bf215546Sopenharmony_ci unsigned int refmasks[3] = { 0, 0, 0 }; 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci unsigned int arg; 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci for(arg = 0; arg < 3; ++arg) { 109bf215546Sopenharmony_ci unsigned int chan; 110bf215546Sopenharmony_ci for(chan = 0; chan < 3; ++chan) { 111bf215546Sopenharmony_ci unsigned int swz_rgb = 112bf215546Sopenharmony_ci GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan); 113bf215546Sopenharmony_ci unsigned int swz_alpha = 114bf215546Sopenharmony_ci GET_SWZ(inst->Alpha.Arg[arg].Swizzle, chan); 115bf215546Sopenharmony_ci pair_get_src_refmasks(refmasks, inst, swz_rgb, 116bf215546Sopenharmony_ci inst->RGB.Arg[arg].Source); 117bf215546Sopenharmony_ci pair_get_src_refmasks(refmasks, inst, swz_alpha, 118bf215546Sopenharmony_ci inst->Alpha.Arg[arg].Source); 119bf215546Sopenharmony_ci } 120bf215546Sopenharmony_ci } 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci for(unsigned int src = 0; src < 3; ++src) { 123bf215546Sopenharmony_ci if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ)) 124bf215546Sopenharmony_ci cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index, 125bf215546Sopenharmony_ci refmasks[src] & RC_MASK_XYZ); 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W)) 128bf215546Sopenharmony_ci cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W); 129bf215546Sopenharmony_ci } 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_cistatic void pair_sub_for_all_args( 133bf215546Sopenharmony_ci struct rc_instruction * fullinst, 134bf215546Sopenharmony_ci struct rc_pair_sub_instruction * sub, 135bf215546Sopenharmony_ci rc_pair_read_arg_fn cb, 136bf215546Sopenharmony_ci void * userdata) 137bf215546Sopenharmony_ci{ 138bf215546Sopenharmony_ci int i; 139bf215546Sopenharmony_ci const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci for(i = 0; i < info->NumSrcRegs; i++) { 142bf215546Sopenharmony_ci unsigned int src_type; 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ci src_type = rc_source_type_swz(sub->Arg[i].Swizzle); 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci if (src_type == RC_SOURCE_NONE) 147bf215546Sopenharmony_ci continue; 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci if (sub->Arg[i].Source == RC_PAIR_PRESUB_SRC) { 150bf215546Sopenharmony_ci unsigned int presub_type; 151bf215546Sopenharmony_ci unsigned int presub_src_count; 152bf215546Sopenharmony_ci struct rc_pair_instruction_source * src_array; 153bf215546Sopenharmony_ci unsigned int j; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci if (src_type & RC_SOURCE_RGB) { 156bf215546Sopenharmony_ci presub_type = fullinst-> 157bf215546Sopenharmony_ci U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index; 158bf215546Sopenharmony_ci src_array = fullinst->U.P.RGB.Src; 159bf215546Sopenharmony_ci } else { 160bf215546Sopenharmony_ci presub_type = fullinst-> 161bf215546Sopenharmony_ci U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index; 162bf215546Sopenharmony_ci src_array = fullinst->U.P.Alpha.Src; 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci presub_src_count 165bf215546Sopenharmony_ci = rc_presubtract_src_reg_count(presub_type); 166bf215546Sopenharmony_ci for(j = 0; j < presub_src_count; j++) { 167bf215546Sopenharmony_ci cb(userdata, fullinst, &sub->Arg[i], 168bf215546Sopenharmony_ci &src_array[j]); 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci } else { 171bf215546Sopenharmony_ci struct rc_pair_instruction_source * src = 172bf215546Sopenharmony_ci rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]); 173bf215546Sopenharmony_ci if (src) { 174bf215546Sopenharmony_ci cb(userdata, fullinst, &sub->Arg[i], src); 175bf215546Sopenharmony_ci } 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci } 178bf215546Sopenharmony_ci} 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci/* This function calls the callback function (cb) for each source used by 181bf215546Sopenharmony_ci * the instruction. 182bf215546Sopenharmony_ci * */ 183bf215546Sopenharmony_civoid rc_for_all_reads_src( 184bf215546Sopenharmony_ci struct rc_instruction * inst, 185bf215546Sopenharmony_ci rc_read_src_fn cb, 186bf215546Sopenharmony_ci void * userdata) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = 189bf215546Sopenharmony_ci rc_get_opcode_info(inst->U.I.Opcode); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci /* This function only works with normal instructions. */ 192bf215546Sopenharmony_ci if (inst->Type != RC_INSTRUCTION_NORMAL) { 193bf215546Sopenharmony_ci assert(0); 194bf215546Sopenharmony_ci return; 195bf215546Sopenharmony_ci } 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) { 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci if (inst->U.I.SrcReg[src].File == RC_FILE_NONE) 200bf215546Sopenharmony_ci continue; 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) { 203bf215546Sopenharmony_ci unsigned int i; 204bf215546Sopenharmony_ci unsigned int srcp_regs = rc_presubtract_src_reg_count( 205bf215546Sopenharmony_ci inst->U.I.PreSub.Opcode); 206bf215546Sopenharmony_ci for( i = 0; i < srcp_regs; i++) { 207bf215546Sopenharmony_ci cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]); 208bf215546Sopenharmony_ci } 209bf215546Sopenharmony_ci } else { 210bf215546Sopenharmony_ci cb(userdata, inst, &inst->U.I.SrcReg[src]); 211bf215546Sopenharmony_ci } 212bf215546Sopenharmony_ci } 213bf215546Sopenharmony_ci} 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci/** 216bf215546Sopenharmony_ci * This function calls the callback function (cb) for each arg of the RGB and 217bf215546Sopenharmony_ci * alpha components. 218bf215546Sopenharmony_ci */ 219bf215546Sopenharmony_civoid rc_pair_for_all_reads_arg( 220bf215546Sopenharmony_ci struct rc_instruction * inst, 221bf215546Sopenharmony_ci rc_pair_read_arg_fn cb, 222bf215546Sopenharmony_ci void * userdata) 223bf215546Sopenharmony_ci{ 224bf215546Sopenharmony_ci /* This function only works with pair instructions. */ 225bf215546Sopenharmony_ci if (inst->Type != RC_INSTRUCTION_PAIR) { 226bf215546Sopenharmony_ci assert(0); 227bf215546Sopenharmony_ci return; 228bf215546Sopenharmony_ci } 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata); 231bf215546Sopenharmony_ci pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata); 232bf215546Sopenharmony_ci} 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci/** 235bf215546Sopenharmony_ci * Calls a callback function for all register reads. 236bf215546Sopenharmony_ci * 237bf215546Sopenharmony_ci * This is conservative, i.e. if the same register is referenced multiple times, 238bf215546Sopenharmony_ci * the callback may also be called multiple times. 239bf215546Sopenharmony_ci * Also, the writemask of the instruction is not taken into account. 240bf215546Sopenharmony_ci */ 241bf215546Sopenharmony_civoid rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata) 242bf215546Sopenharmony_ci{ 243bf215546Sopenharmony_ci if (inst->Type == RC_INSTRUCTION_NORMAL) { 244bf215546Sopenharmony_ci struct read_write_mask_data cb_data; 245bf215546Sopenharmony_ci cb_data.UserData = userdata; 246bf215546Sopenharmony_ci cb_data.Cb = cb; 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci rc_for_all_reads_src(inst, reads_normal_callback, &cb_data); 249bf215546Sopenharmony_ci } else { 250bf215546Sopenharmony_ci reads_pair(inst, cb, userdata); 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci} 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_cistatic void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) 257bf215546Sopenharmony_ci{ 258bf215546Sopenharmony_ci struct rc_sub_instruction * inst = &fullinst->U.I; 259bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode); 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci if (opcode->HasDstReg && inst->DstReg.WriteMask) 262bf215546Sopenharmony_ci cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask); 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci if (inst->WriteALUResult) 265bf215546Sopenharmony_ci cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X); 266bf215546Sopenharmony_ci} 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_cistatic void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) 269bf215546Sopenharmony_ci{ 270bf215546Sopenharmony_ci struct rc_pair_instruction * inst = &fullinst->U.P; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci if (inst->RGB.WriteMask) 273bf215546Sopenharmony_ci cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask); 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci if (inst->Alpha.WriteMask) 276bf215546Sopenharmony_ci cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W); 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci if (inst->WriteALUResult) 279bf215546Sopenharmony_ci cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X); 280bf215546Sopenharmony_ci} 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci/** 283bf215546Sopenharmony_ci * Calls a callback function for all register writes in the instruction, 284bf215546Sopenharmony_ci * reporting writemasks to the callback function. 285bf215546Sopenharmony_ci * 286bf215546Sopenharmony_ci * \warning Does not report output registers for paired instructions! 287bf215546Sopenharmony_ci */ 288bf215546Sopenharmony_civoid rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata) 289bf215546Sopenharmony_ci{ 290bf215546Sopenharmony_ci if (inst->Type == RC_INSTRUCTION_NORMAL) { 291bf215546Sopenharmony_ci writes_normal(inst, cb, userdata); 292bf215546Sopenharmony_ci } else { 293bf215546Sopenharmony_ci writes_pair(inst, cb, userdata); 294bf215546Sopenharmony_ci } 295bf215546Sopenharmony_ci} 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_cistruct mask_to_chan_data { 299bf215546Sopenharmony_ci void * UserData; 300bf215546Sopenharmony_ci rc_read_write_chan_fn Fn; 301bf215546Sopenharmony_ci}; 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_cistatic void mask_to_chan_cb(void * data, struct rc_instruction * inst, 304bf215546Sopenharmony_ci rc_register_file file, unsigned int index, unsigned int mask) 305bf215546Sopenharmony_ci{ 306bf215546Sopenharmony_ci struct mask_to_chan_data * d = data; 307bf215546Sopenharmony_ci for(unsigned int chan = 0; chan < 4; ++chan) { 308bf215546Sopenharmony_ci if (GET_BIT(mask, chan)) 309bf215546Sopenharmony_ci d->Fn(d->UserData, inst, file, index, chan); 310bf215546Sopenharmony_ci } 311bf215546Sopenharmony_ci} 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci/** 314bf215546Sopenharmony_ci * Calls a callback function for all sourced register channels. 315bf215546Sopenharmony_ci * 316bf215546Sopenharmony_ci * This is conservative, i.e. channels may be called multiple times, 317bf215546Sopenharmony_ci * and the writemask of the instruction is not taken into account. 318bf215546Sopenharmony_ci */ 319bf215546Sopenharmony_civoid rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata) 320bf215546Sopenharmony_ci{ 321bf215546Sopenharmony_ci struct mask_to_chan_data d; 322bf215546Sopenharmony_ci d.UserData = userdata; 323bf215546Sopenharmony_ci d.Fn = cb; 324bf215546Sopenharmony_ci rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d); 325bf215546Sopenharmony_ci} 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci/** 328bf215546Sopenharmony_ci * Calls a callback function for all written register channels. 329bf215546Sopenharmony_ci * 330bf215546Sopenharmony_ci * \warning Does not report output registers for paired instructions! 331bf215546Sopenharmony_ci */ 332bf215546Sopenharmony_civoid rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata) 333bf215546Sopenharmony_ci{ 334bf215546Sopenharmony_ci struct mask_to_chan_data d; 335bf215546Sopenharmony_ci d.UserData = userdata; 336bf215546Sopenharmony_ci d.Fn = cb; 337bf215546Sopenharmony_ci rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d); 338bf215546Sopenharmony_ci} 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_cistatic void remap_normal_instruction(struct rc_instruction * fullinst, 341bf215546Sopenharmony_ci rc_remap_register_fn cb, void * userdata) 342bf215546Sopenharmony_ci{ 343bf215546Sopenharmony_ci struct rc_sub_instruction * inst = &fullinst->U.I; 344bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode); 345bf215546Sopenharmony_ci unsigned int remapped_presub = 0; 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci if (opcode->HasDstReg) { 348bf215546Sopenharmony_ci rc_register_file file = inst->DstReg.File; 349bf215546Sopenharmony_ci unsigned int index = inst->DstReg.Index; 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci cb(userdata, fullinst, &file, &index); 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci inst->DstReg.File = file; 354bf215546Sopenharmony_ci inst->DstReg.Index = index; 355bf215546Sopenharmony_ci } 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) { 358bf215546Sopenharmony_ci rc_register_file file = inst->SrcReg[src].File; 359bf215546Sopenharmony_ci unsigned int index = inst->SrcReg[src].Index; 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci if (file == RC_FILE_PRESUB) { 362bf215546Sopenharmony_ci unsigned int i; 363bf215546Sopenharmony_ci unsigned int srcp_srcs = rc_presubtract_src_reg_count( 364bf215546Sopenharmony_ci inst->PreSub.Opcode); 365bf215546Sopenharmony_ci /* Make sure we only remap presubtract sources once in 366bf215546Sopenharmony_ci * case more than one source register reads the 367bf215546Sopenharmony_ci * presubtract result. */ 368bf215546Sopenharmony_ci if (remapped_presub) 369bf215546Sopenharmony_ci continue; 370bf215546Sopenharmony_ci 371bf215546Sopenharmony_ci for(i = 0; i < srcp_srcs; i++) { 372bf215546Sopenharmony_ci file = inst->PreSub.SrcReg[i].File; 373bf215546Sopenharmony_ci index = inst->PreSub.SrcReg[i].Index; 374bf215546Sopenharmony_ci cb(userdata, fullinst, &file, &index); 375bf215546Sopenharmony_ci inst->PreSub.SrcReg[i].File = file; 376bf215546Sopenharmony_ci inst->PreSub.SrcReg[i].Index = index; 377bf215546Sopenharmony_ci } 378bf215546Sopenharmony_ci remapped_presub = 1; 379bf215546Sopenharmony_ci } 380bf215546Sopenharmony_ci else { 381bf215546Sopenharmony_ci cb(userdata, fullinst, &file, &index); 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci inst->SrcReg[src].File = file; 384bf215546Sopenharmony_ci inst->SrcReg[src].Index = index; 385bf215546Sopenharmony_ci } 386bf215546Sopenharmony_ci } 387bf215546Sopenharmony_ci} 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_cistatic void remap_pair_instruction(struct rc_instruction * fullinst, 390bf215546Sopenharmony_ci rc_remap_register_fn cb, void * userdata) 391bf215546Sopenharmony_ci{ 392bf215546Sopenharmony_ci struct rc_pair_instruction * inst = &fullinst->U.P; 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci if (inst->RGB.WriteMask) { 395bf215546Sopenharmony_ci rc_register_file file = RC_FILE_TEMPORARY; 396bf215546Sopenharmony_ci unsigned int index = inst->RGB.DestIndex; 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci cb(userdata, fullinst, &file, &index); 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci inst->RGB.DestIndex = index; 401bf215546Sopenharmony_ci } 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci if (inst->Alpha.WriteMask) { 404bf215546Sopenharmony_ci rc_register_file file = RC_FILE_TEMPORARY; 405bf215546Sopenharmony_ci unsigned int index = inst->Alpha.DestIndex; 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci cb(userdata, fullinst, &file, &index); 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci inst->Alpha.DestIndex = index; 410bf215546Sopenharmony_ci } 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci for(unsigned int src = 0; src < 3; ++src) { 413bf215546Sopenharmony_ci if (inst->RGB.Src[src].Used) { 414bf215546Sopenharmony_ci rc_register_file file = inst->RGB.Src[src].File; 415bf215546Sopenharmony_ci unsigned int index = inst->RGB.Src[src].Index; 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_ci cb(userdata, fullinst, &file, &index); 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci inst->RGB.Src[src].File = file; 420bf215546Sopenharmony_ci inst->RGB.Src[src].Index = index; 421bf215546Sopenharmony_ci } 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci if (inst->Alpha.Src[src].Used) { 424bf215546Sopenharmony_ci rc_register_file file = inst->Alpha.Src[src].File; 425bf215546Sopenharmony_ci unsigned int index = inst->Alpha.Src[src].Index; 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci cb(userdata, fullinst, &file, &index); 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci inst->Alpha.Src[src].File = file; 430bf215546Sopenharmony_ci inst->Alpha.Src[src].Index = index; 431bf215546Sopenharmony_ci } 432bf215546Sopenharmony_ci } 433bf215546Sopenharmony_ci} 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_ci 436bf215546Sopenharmony_ci/** 437bf215546Sopenharmony_ci * Remap all register accesses according to the given function. 438bf215546Sopenharmony_ci * That is, call the function \p cb for each referenced register (both read and written) 439bf215546Sopenharmony_ci * and update the given instruction \p inst accordingly 440bf215546Sopenharmony_ci * if it modifies its \ref pfile and \ref pindex contents. 441bf215546Sopenharmony_ci */ 442bf215546Sopenharmony_civoid rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata) 443bf215546Sopenharmony_ci{ 444bf215546Sopenharmony_ci if (inst->Type == RC_INSTRUCTION_NORMAL) 445bf215546Sopenharmony_ci remap_normal_instruction(inst, cb, userdata); 446bf215546Sopenharmony_ci else 447bf215546Sopenharmony_ci remap_pair_instruction(inst, cb, userdata); 448bf215546Sopenharmony_ci} 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_cistruct branch_write_mask { 451bf215546Sopenharmony_ci unsigned int IfWriteMask:4; 452bf215546Sopenharmony_ci unsigned int ElseWriteMask:4; 453bf215546Sopenharmony_ci unsigned int HasElse:1; 454bf215546Sopenharmony_ci}; 455bf215546Sopenharmony_ci 456bf215546Sopenharmony_ciunion get_readers_read_cb { 457bf215546Sopenharmony_ci rc_read_src_fn I; 458bf215546Sopenharmony_ci rc_pair_read_arg_fn P; 459bf215546Sopenharmony_ci}; 460bf215546Sopenharmony_ci 461bf215546Sopenharmony_cistruct get_readers_callback_data { 462bf215546Sopenharmony_ci struct radeon_compiler * C; 463bf215546Sopenharmony_ci struct rc_reader_data * ReaderData; 464bf215546Sopenharmony_ci rc_read_src_fn ReadNormalCB; 465bf215546Sopenharmony_ci rc_pair_read_arg_fn ReadPairCB; 466bf215546Sopenharmony_ci rc_read_write_mask_fn WriteCB; 467bf215546Sopenharmony_ci rc_register_file DstFile; 468bf215546Sopenharmony_ci unsigned int DstIndex; 469bf215546Sopenharmony_ci unsigned int DstMask; 470bf215546Sopenharmony_ci unsigned int AliveWriteMask; 471bf215546Sopenharmony_ci /* For convenience, this is indexed starting at 1 */ 472bf215546Sopenharmony_ci struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1]; 473bf215546Sopenharmony_ci}; 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_cistatic struct rc_reader * add_reader( 476bf215546Sopenharmony_ci struct memory_pool * pool, 477bf215546Sopenharmony_ci struct rc_reader_data * data, 478bf215546Sopenharmony_ci struct rc_instruction * inst, 479bf215546Sopenharmony_ci unsigned int mask) 480bf215546Sopenharmony_ci{ 481bf215546Sopenharmony_ci struct rc_reader * new; 482bf215546Sopenharmony_ci memory_pool_array_reserve(pool, struct rc_reader, data->Readers, 483bf215546Sopenharmony_ci data->ReaderCount, data->ReadersReserved, 1); 484bf215546Sopenharmony_ci new = &data->Readers[data->ReaderCount++]; 485bf215546Sopenharmony_ci new->Inst = inst; 486bf215546Sopenharmony_ci new->WriteMask = mask; 487bf215546Sopenharmony_ci return new; 488bf215546Sopenharmony_ci} 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_cistatic void add_reader_normal( 491bf215546Sopenharmony_ci struct memory_pool * pool, 492bf215546Sopenharmony_ci struct rc_reader_data * data, 493bf215546Sopenharmony_ci struct rc_instruction * inst, 494bf215546Sopenharmony_ci unsigned int mask, 495bf215546Sopenharmony_ci struct rc_src_register * src) 496bf215546Sopenharmony_ci{ 497bf215546Sopenharmony_ci struct rc_reader * new = add_reader(pool, data, inst, mask); 498bf215546Sopenharmony_ci new->U.I.Src = src; 499bf215546Sopenharmony_ci} 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci 502bf215546Sopenharmony_cistatic void add_reader_pair( 503bf215546Sopenharmony_ci struct memory_pool * pool, 504bf215546Sopenharmony_ci struct rc_reader_data * data, 505bf215546Sopenharmony_ci struct rc_instruction * inst, 506bf215546Sopenharmony_ci unsigned int mask, 507bf215546Sopenharmony_ci struct rc_pair_instruction_arg * arg, 508bf215546Sopenharmony_ci struct rc_pair_instruction_source * src) 509bf215546Sopenharmony_ci{ 510bf215546Sopenharmony_ci struct rc_reader * new = add_reader(pool, data, inst, mask); 511bf215546Sopenharmony_ci new->U.P.Src = src; 512bf215546Sopenharmony_ci new->U.P.Arg = arg; 513bf215546Sopenharmony_ci} 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_cistatic unsigned int get_readers_read_callback( 516bf215546Sopenharmony_ci struct get_readers_callback_data * cb_data, 517bf215546Sopenharmony_ci unsigned int has_rel_addr, 518bf215546Sopenharmony_ci rc_register_file file, 519bf215546Sopenharmony_ci unsigned int index, 520bf215546Sopenharmony_ci unsigned int swizzle) 521bf215546Sopenharmony_ci{ 522bf215546Sopenharmony_ci unsigned int shared_mask, read_mask; 523bf215546Sopenharmony_ci 524bf215546Sopenharmony_ci if (has_rel_addr) { 525bf215546Sopenharmony_ci cb_data->ReaderData->Abort = 1; 526bf215546Sopenharmony_ci return RC_MASK_NONE; 527bf215546Sopenharmony_ci } 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci shared_mask = rc_src_reads_dst_mask(file, index, swizzle, 530bf215546Sopenharmony_ci cb_data->DstFile, cb_data->DstIndex, cb_data->AliveWriteMask); 531bf215546Sopenharmony_ci 532bf215546Sopenharmony_ci if (shared_mask == RC_MASK_NONE) 533bf215546Sopenharmony_ci return shared_mask; 534bf215546Sopenharmony_ci 535bf215546Sopenharmony_ci /* If we make it this far, it means that this source reads from the 536bf215546Sopenharmony_ci * same register written to by d->ReaderData->Writer. */ 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci read_mask = rc_swizzle_to_writemask(swizzle); 539bf215546Sopenharmony_ci if (cb_data->ReaderData->AbortOnRead & read_mask) { 540bf215546Sopenharmony_ci cb_data->ReaderData->Abort = 1; 541bf215546Sopenharmony_ci return shared_mask; 542bf215546Sopenharmony_ci } 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci if (cb_data->ReaderData->LoopDepth > 0) { 545bf215546Sopenharmony_ci cb_data->ReaderData->AbortOnWrite |= 546bf215546Sopenharmony_ci (read_mask & cb_data->AliveWriteMask); 547bf215546Sopenharmony_ci } 548bf215546Sopenharmony_ci 549bf215546Sopenharmony_ci /* XXX The behavior in this case should be configurable. */ 550bf215546Sopenharmony_ci if ((read_mask & cb_data->AliveWriteMask) != read_mask) { 551bf215546Sopenharmony_ci cb_data->ReaderData->Abort = 1; 552bf215546Sopenharmony_ci return shared_mask; 553bf215546Sopenharmony_ci } 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci return shared_mask; 556bf215546Sopenharmony_ci} 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_cistatic void get_readers_pair_read_callback( 559bf215546Sopenharmony_ci void * userdata, 560bf215546Sopenharmony_ci struct rc_instruction * inst, 561bf215546Sopenharmony_ci struct rc_pair_instruction_arg * arg, 562bf215546Sopenharmony_ci struct rc_pair_instruction_source * src) 563bf215546Sopenharmony_ci{ 564bf215546Sopenharmony_ci unsigned int shared_mask; 565bf215546Sopenharmony_ci struct get_readers_callback_data * d = userdata; 566bf215546Sopenharmony_ci 567bf215546Sopenharmony_ci shared_mask = get_readers_read_callback(d, 568bf215546Sopenharmony_ci 0 /*Pair Instructions don't use RelAddr*/, 569bf215546Sopenharmony_ci src->File, src->Index, arg->Swizzle); 570bf215546Sopenharmony_ci 571bf215546Sopenharmony_ci if (shared_mask == RC_MASK_NONE) 572bf215546Sopenharmony_ci return; 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_ci if (d->ReadPairCB) 575bf215546Sopenharmony_ci d->ReadPairCB(d->ReaderData, inst, arg, src); 576bf215546Sopenharmony_ci 577bf215546Sopenharmony_ci if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) 578bf215546Sopenharmony_ci return; 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ci add_reader_pair(&d->C->Pool, d->ReaderData, inst, shared_mask, arg, src); 581bf215546Sopenharmony_ci} 582bf215546Sopenharmony_ci 583bf215546Sopenharmony_ci/** 584bf215546Sopenharmony_ci * This function is used by rc_get_readers_normal() to determine whether inst 585bf215546Sopenharmony_ci * is a reader of userdata->ReaderData->Writer 586bf215546Sopenharmony_ci */ 587bf215546Sopenharmony_cistatic void get_readers_normal_read_callback( 588bf215546Sopenharmony_ci void * userdata, 589bf215546Sopenharmony_ci struct rc_instruction * inst, 590bf215546Sopenharmony_ci struct rc_src_register * src) 591bf215546Sopenharmony_ci{ 592bf215546Sopenharmony_ci struct get_readers_callback_data * d = userdata; 593bf215546Sopenharmony_ci unsigned int shared_mask; 594bf215546Sopenharmony_ci 595bf215546Sopenharmony_ci shared_mask = get_readers_read_callback(d, 596bf215546Sopenharmony_ci src->RelAddr, src->File, src->Index, src->Swizzle); 597bf215546Sopenharmony_ci 598bf215546Sopenharmony_ci if (shared_mask == RC_MASK_NONE) 599bf215546Sopenharmony_ci return; 600bf215546Sopenharmony_ci /* The callback function could potentially clear d->ReaderData->Abort, 601bf215546Sopenharmony_ci * so we need to call it before we return. */ 602bf215546Sopenharmony_ci if (d->ReadNormalCB) 603bf215546Sopenharmony_ci d->ReadNormalCB(d->ReaderData, inst, src); 604bf215546Sopenharmony_ci 605bf215546Sopenharmony_ci if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) 606bf215546Sopenharmony_ci return; 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci add_reader_normal(&d->C->Pool, d->ReaderData, inst, shared_mask, src); 609bf215546Sopenharmony_ci} 610bf215546Sopenharmony_ci 611bf215546Sopenharmony_ci/** 612bf215546Sopenharmony_ci * This function is used by rc_get_readers_normal() to determine when 613bf215546Sopenharmony_ci * userdata->ReaderData->Writer is dead (i. e. All components of its 614bf215546Sopenharmony_ci * destination register have been overwritten by other instructions). 615bf215546Sopenharmony_ci */ 616bf215546Sopenharmony_cistatic void get_readers_write_callback( 617bf215546Sopenharmony_ci void *userdata, 618bf215546Sopenharmony_ci struct rc_instruction * inst, 619bf215546Sopenharmony_ci rc_register_file file, 620bf215546Sopenharmony_ci unsigned int index, 621bf215546Sopenharmony_ci unsigned int mask) 622bf215546Sopenharmony_ci{ 623bf215546Sopenharmony_ci struct get_readers_callback_data * d = userdata; 624bf215546Sopenharmony_ci 625bf215546Sopenharmony_ci if (index == d->DstIndex && file == d->DstFile) { 626bf215546Sopenharmony_ci unsigned int shared_mask = mask & d->DstMask; 627bf215546Sopenharmony_ci d->ReaderData->AbortOnRead &= ~shared_mask; 628bf215546Sopenharmony_ci d->AliveWriteMask &= ~shared_mask; 629bf215546Sopenharmony_ci if (d->ReaderData->AbortOnWrite & shared_mask) { 630bf215546Sopenharmony_ci d->ReaderData->Abort = 1; 631bf215546Sopenharmony_ci } 632bf215546Sopenharmony_ci } 633bf215546Sopenharmony_ci 634bf215546Sopenharmony_ci if(d->WriteCB) 635bf215546Sopenharmony_ci d->WriteCB(d->ReaderData, inst, file, index, mask); 636bf215546Sopenharmony_ci} 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_cistatic void push_branch_mask( 639bf215546Sopenharmony_ci struct get_readers_callback_data * d, 640bf215546Sopenharmony_ci unsigned int * branch_depth) 641bf215546Sopenharmony_ci{ 642bf215546Sopenharmony_ci (*branch_depth)++; 643bf215546Sopenharmony_ci if (*branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) { 644bf215546Sopenharmony_ci d->ReaderData->Abort = 1; 645bf215546Sopenharmony_ci return; 646bf215546Sopenharmony_ci } 647bf215546Sopenharmony_ci d->BranchMasks[*branch_depth].IfWriteMask = 648bf215546Sopenharmony_ci d->AliveWriteMask; 649bf215546Sopenharmony_ci} 650bf215546Sopenharmony_ci 651bf215546Sopenharmony_cistatic void pop_branch_mask( 652bf215546Sopenharmony_ci struct get_readers_callback_data * d, 653bf215546Sopenharmony_ci unsigned int * branch_depth) 654bf215546Sopenharmony_ci{ 655bf215546Sopenharmony_ci struct branch_write_mask * masks = &d->BranchMasks[*branch_depth]; 656bf215546Sopenharmony_ci 657bf215546Sopenharmony_ci if (masks->HasElse) { 658bf215546Sopenharmony_ci /* Abort on read for components that were written in the IF 659bf215546Sopenharmony_ci * block. */ 660bf215546Sopenharmony_ci d->ReaderData->AbortOnRead |= 661bf215546Sopenharmony_ci masks->IfWriteMask & ~masks->ElseWriteMask; 662bf215546Sopenharmony_ci /* Abort on read for components that were written in the ELSE 663bf215546Sopenharmony_ci * block. */ 664bf215546Sopenharmony_ci d->ReaderData->AbortOnRead |= 665bf215546Sopenharmony_ci masks->ElseWriteMask & ~d->AliveWriteMask; 666bf215546Sopenharmony_ci 667bf215546Sopenharmony_ci d->AliveWriteMask = masks->IfWriteMask 668bf215546Sopenharmony_ci ^ ((masks->IfWriteMask ^ masks->ElseWriteMask) 669bf215546Sopenharmony_ci & (masks->IfWriteMask ^ d->AliveWriteMask)); 670bf215546Sopenharmony_ci } else { 671bf215546Sopenharmony_ci d->ReaderData->AbortOnRead |= 672bf215546Sopenharmony_ci masks->IfWriteMask & ~d->AliveWriteMask; 673bf215546Sopenharmony_ci d->AliveWriteMask = masks->IfWriteMask; 674bf215546Sopenharmony_ci 675bf215546Sopenharmony_ci } 676bf215546Sopenharmony_ci memset(masks, 0, sizeof(struct branch_write_mask)); 677bf215546Sopenharmony_ci (*branch_depth)--; 678bf215546Sopenharmony_ci} 679bf215546Sopenharmony_ci 680bf215546Sopenharmony_cistatic void get_readers_for_single_write( 681bf215546Sopenharmony_ci void * userdata, 682bf215546Sopenharmony_ci struct rc_instruction * writer, 683bf215546Sopenharmony_ci rc_register_file dst_file, 684bf215546Sopenharmony_ci unsigned int dst_index, 685bf215546Sopenharmony_ci unsigned int dst_mask) 686bf215546Sopenharmony_ci{ 687bf215546Sopenharmony_ci struct rc_instruction * tmp; 688bf215546Sopenharmony_ci unsigned int branch_depth = 0; 689bf215546Sopenharmony_ci struct rc_instruction * endloop = NULL; 690bf215546Sopenharmony_ci unsigned int abort_on_read_at_endloop = 0; 691bf215546Sopenharmony_ci int readers_before_endloop = -1; 692bf215546Sopenharmony_ci struct get_readers_callback_data * d = userdata; 693bf215546Sopenharmony_ci 694bf215546Sopenharmony_ci d->ReaderData->Writer = writer; 695bf215546Sopenharmony_ci d->ReaderData->AbortOnRead = 0; 696bf215546Sopenharmony_ci d->ReaderData->AbortOnWrite = 0; 697bf215546Sopenharmony_ci d->ReaderData->LoopDepth = 0; 698bf215546Sopenharmony_ci d->ReaderData->InElse = 0; 699bf215546Sopenharmony_ci d->ReaderData->ReadersAfterEndloop = false; 700bf215546Sopenharmony_ci d->DstFile = dst_file; 701bf215546Sopenharmony_ci d->DstIndex = dst_index; 702bf215546Sopenharmony_ci d->DstMask = dst_mask; 703bf215546Sopenharmony_ci d->AliveWriteMask = dst_mask; 704bf215546Sopenharmony_ci memset(d->BranchMasks, 0, sizeof(d->BranchMasks)); 705bf215546Sopenharmony_ci 706bf215546Sopenharmony_ci if (!dst_mask) 707bf215546Sopenharmony_ci return; 708bf215546Sopenharmony_ci 709bf215546Sopenharmony_ci for(tmp = writer->Next; tmp != &d->C->Program.Instructions; 710bf215546Sopenharmony_ci tmp = tmp->Next){ 711bf215546Sopenharmony_ci rc_opcode opcode = rc_get_flow_control_inst(tmp); 712bf215546Sopenharmony_ci switch(opcode) { 713bf215546Sopenharmony_ci case RC_OPCODE_BGNLOOP: 714bf215546Sopenharmony_ci d->ReaderData->LoopDepth++; 715bf215546Sopenharmony_ci push_branch_mask(d, &branch_depth); 716bf215546Sopenharmony_ci break; 717bf215546Sopenharmony_ci case RC_OPCODE_ENDLOOP: 718bf215546Sopenharmony_ci if (d->ReaderData->LoopDepth > 0) { 719bf215546Sopenharmony_ci d->ReaderData->LoopDepth--; 720bf215546Sopenharmony_ci if (d->ReaderData->LoopDepth == 0) { 721bf215546Sopenharmony_ci d->ReaderData->AbortOnWrite = 0; 722bf215546Sopenharmony_ci } 723bf215546Sopenharmony_ci pop_branch_mask(d, &branch_depth); 724bf215546Sopenharmony_ci } else { 725bf215546Sopenharmony_ci /* Here we have reached an ENDLOOP without 726bf215546Sopenharmony_ci * seeing its BGNLOOP. These means that 727bf215546Sopenharmony_ci * the writer was written inside of a loop, 728bf215546Sopenharmony_ci * so it could have readers that are above it 729bf215546Sopenharmony_ci * (i.e. they have a lower IP). To find these 730bf215546Sopenharmony_ci * readers we jump to the BGNLOOP instruction 731bf215546Sopenharmony_ci * and check each instruction until we get 732bf215546Sopenharmony_ci * back to the writer. 733bf215546Sopenharmony_ci */ 734bf215546Sopenharmony_ci endloop = tmp; 735bf215546Sopenharmony_ci tmp = rc_match_endloop(tmp); 736bf215546Sopenharmony_ci if (!tmp) { 737bf215546Sopenharmony_ci rc_error(d->C, "Failed to match endloop.\n"); 738bf215546Sopenharmony_ci d->ReaderData->Abort = 1; 739bf215546Sopenharmony_ci return; 740bf215546Sopenharmony_ci } 741bf215546Sopenharmony_ci abort_on_read_at_endloop = d->ReaderData->AbortOnRead; 742bf215546Sopenharmony_ci d->ReaderData->AbortOnRead |= d->AliveWriteMask; 743bf215546Sopenharmony_ci continue; 744bf215546Sopenharmony_ci } 745bf215546Sopenharmony_ci break; 746bf215546Sopenharmony_ci case RC_OPCODE_IF: 747bf215546Sopenharmony_ci push_branch_mask(d, &branch_depth); 748bf215546Sopenharmony_ci break; 749bf215546Sopenharmony_ci case RC_OPCODE_ELSE: 750bf215546Sopenharmony_ci if (branch_depth == 0) { 751bf215546Sopenharmony_ci d->ReaderData->InElse = 1; 752bf215546Sopenharmony_ci } else { 753bf215546Sopenharmony_ci unsigned int temp_mask = d->AliveWriteMask; 754bf215546Sopenharmony_ci d->AliveWriteMask = 755bf215546Sopenharmony_ci d->BranchMasks[branch_depth].IfWriteMask; 756bf215546Sopenharmony_ci d->BranchMasks[branch_depth].ElseWriteMask = 757bf215546Sopenharmony_ci temp_mask; 758bf215546Sopenharmony_ci d->BranchMasks[branch_depth].HasElse = 1; 759bf215546Sopenharmony_ci } 760bf215546Sopenharmony_ci break; 761bf215546Sopenharmony_ci case RC_OPCODE_ENDIF: 762bf215546Sopenharmony_ci if (branch_depth == 0) { 763bf215546Sopenharmony_ci d->ReaderData->AbortOnRead = d->AliveWriteMask; 764bf215546Sopenharmony_ci d->ReaderData->InElse = 0; 765bf215546Sopenharmony_ci } 766bf215546Sopenharmony_ci else { 767bf215546Sopenharmony_ci pop_branch_mask(d, &branch_depth); 768bf215546Sopenharmony_ci } 769bf215546Sopenharmony_ci break; 770bf215546Sopenharmony_ci default: 771bf215546Sopenharmony_ci break; 772bf215546Sopenharmony_ci } 773bf215546Sopenharmony_ci 774bf215546Sopenharmony_ci if (d->ReaderData->InElse) 775bf215546Sopenharmony_ci continue; 776bf215546Sopenharmony_ci 777bf215546Sopenharmony_ci if (tmp->Type == RC_INSTRUCTION_NORMAL) { 778bf215546Sopenharmony_ci rc_for_all_reads_src(tmp, 779bf215546Sopenharmony_ci get_readers_normal_read_callback, d); 780bf215546Sopenharmony_ci } else { 781bf215546Sopenharmony_ci rc_pair_for_all_reads_arg(tmp, 782bf215546Sopenharmony_ci get_readers_pair_read_callback, d); 783bf215546Sopenharmony_ci } 784bf215546Sopenharmony_ci 785bf215546Sopenharmony_ci /* Writer was in loop and we have some readers after it. 786bf215546Sopenharmony_ci * Set a flag so we can be extra careful in copy propagate. 787bf215546Sopenharmony_ci */ 788bf215546Sopenharmony_ci if (readers_before_endloop != -1 && 789bf215546Sopenharmony_ci d->ReaderData->ReaderCount > readers_before_endloop) 790bf215546Sopenharmony_ci d->ReaderData->ReadersAfterEndloop = true; 791bf215546Sopenharmony_ci 792bf215546Sopenharmony_ci /* This can happen when we jump from an ENDLOOP to BGNLOOP */ 793bf215546Sopenharmony_ci if (tmp == writer) { 794bf215546Sopenharmony_ci tmp = endloop; 795bf215546Sopenharmony_ci endloop = NULL; 796bf215546Sopenharmony_ci d->ReaderData->AbortOnRead = abort_on_read_at_endloop; 797bf215546Sopenharmony_ci readers_before_endloop = d->ReaderData->ReaderCount; 798bf215546Sopenharmony_ci continue; 799bf215546Sopenharmony_ci } 800bf215546Sopenharmony_ci rc_for_all_writes_mask(tmp, get_readers_write_callback, d); 801bf215546Sopenharmony_ci 802bf215546Sopenharmony_ci if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) 803bf215546Sopenharmony_ci return; 804bf215546Sopenharmony_ci 805bf215546Sopenharmony_ci if (branch_depth == 0 && !d->AliveWriteMask) 806bf215546Sopenharmony_ci return; 807bf215546Sopenharmony_ci } 808bf215546Sopenharmony_ci} 809bf215546Sopenharmony_ci 810bf215546Sopenharmony_cistatic void init_get_readers_callback_data( 811bf215546Sopenharmony_ci struct get_readers_callback_data * d, 812bf215546Sopenharmony_ci struct rc_reader_data * reader_data, 813bf215546Sopenharmony_ci struct radeon_compiler * c, 814bf215546Sopenharmony_ci rc_read_src_fn read_normal_cb, 815bf215546Sopenharmony_ci rc_pair_read_arg_fn read_pair_cb, 816bf215546Sopenharmony_ci rc_read_write_mask_fn write_cb) 817bf215546Sopenharmony_ci{ 818bf215546Sopenharmony_ci reader_data->Abort = 0; 819bf215546Sopenharmony_ci reader_data->ReaderCount = 0; 820bf215546Sopenharmony_ci reader_data->ReadersReserved = 0; 821bf215546Sopenharmony_ci reader_data->Readers = NULL; 822bf215546Sopenharmony_ci 823bf215546Sopenharmony_ci d->C = c; 824bf215546Sopenharmony_ci d->ReaderData = reader_data; 825bf215546Sopenharmony_ci d->ReadNormalCB = read_normal_cb; 826bf215546Sopenharmony_ci d->ReadPairCB = read_pair_cb; 827bf215546Sopenharmony_ci d->WriteCB = write_cb; 828bf215546Sopenharmony_ci} 829bf215546Sopenharmony_ci 830bf215546Sopenharmony_ci/** 831bf215546Sopenharmony_ci * This function will create a list of readers via the rc_reader_data struct. 832bf215546Sopenharmony_ci * This function will abort (set the flag data->Abort) and return if it 833bf215546Sopenharmony_ci * encounters an instruction that reads from @param writer and also a different 834bf215546Sopenharmony_ci * instruction. Here are some examples: 835bf215546Sopenharmony_ci * 836bf215546Sopenharmony_ci * writer = instruction 0; 837bf215546Sopenharmony_ci * 0 MOV TEMP[0].xy, TEMP[1].xy 838bf215546Sopenharmony_ci * 1 MOV TEMP[0].zw, TEMP[2].xy 839bf215546Sopenharmony_ci * 2 MOV TEMP[3], TEMP[0] 840bf215546Sopenharmony_ci * The Abort flag will be set on instruction 2, because it reads values written 841bf215546Sopenharmony_ci * by instructions 0 and 1. 842bf215546Sopenharmony_ci * 843bf215546Sopenharmony_ci * writer = instruction 1; 844bf215546Sopenharmony_ci * 0 IF TEMP[0].x 845bf215546Sopenharmony_ci * 1 MOV TEMP[1], TEMP[2] 846bf215546Sopenharmony_ci * 2 ELSE 847bf215546Sopenharmony_ci * 3 MOV TEMP[1], TEMP[2] 848bf215546Sopenharmony_ci * 4 ENDIF 849bf215546Sopenharmony_ci * 5 MOV TEMP[3], TEMP[1] 850bf215546Sopenharmony_ci * The Abort flag will be set on instruction 5, because it could read from the 851bf215546Sopenharmony_ci * value written by either instruction 1 or 3, depending on the jump decision 852bf215546Sopenharmony_ci * made at instruction 0. 853bf215546Sopenharmony_ci * 854bf215546Sopenharmony_ci * writer = instruction 0; 855bf215546Sopenharmony_ci * 0 MOV TEMP[0], TEMP[1] 856bf215546Sopenharmony_ci * 2 BGNLOOP 857bf215546Sopenharmony_ci * 3 ADD TEMP[0], TEMP[0], none.1 858bf215546Sopenharmony_ci * 4 ENDLOOP 859bf215546Sopenharmony_ci * The Abort flag will be set on instruction 3, because in the first iteration 860bf215546Sopenharmony_ci * of the loop it reads the value written by instruction 0 and in all other 861bf215546Sopenharmony_ci * iterations it reads the value written by instruction 3. 862bf215546Sopenharmony_ci * 863bf215546Sopenharmony_ci * @param read_cb This function will be called for every instruction that 864bf215546Sopenharmony_ci * has been determined to be a reader of writer. 865bf215546Sopenharmony_ci * @param write_cb This function will be called for every instruction after 866bf215546Sopenharmony_ci * writer. 867bf215546Sopenharmony_ci */ 868bf215546Sopenharmony_civoid rc_get_readers( 869bf215546Sopenharmony_ci struct radeon_compiler * c, 870bf215546Sopenharmony_ci struct rc_instruction * writer, 871bf215546Sopenharmony_ci struct rc_reader_data * data, 872bf215546Sopenharmony_ci rc_read_src_fn read_normal_cb, 873bf215546Sopenharmony_ci rc_pair_read_arg_fn read_pair_cb, 874bf215546Sopenharmony_ci rc_read_write_mask_fn write_cb) 875bf215546Sopenharmony_ci{ 876bf215546Sopenharmony_ci struct get_readers_callback_data d; 877bf215546Sopenharmony_ci 878bf215546Sopenharmony_ci init_get_readers_callback_data(&d, data, c, read_normal_cb, 879bf215546Sopenharmony_ci read_pair_cb, write_cb); 880bf215546Sopenharmony_ci 881bf215546Sopenharmony_ci rc_for_all_writes_mask(writer, get_readers_for_single_write, &d); 882bf215546Sopenharmony_ci} 883bf215546Sopenharmony_ci 884bf215546Sopenharmony_civoid rc_get_readers_sub( 885bf215546Sopenharmony_ci struct radeon_compiler * c, 886bf215546Sopenharmony_ci struct rc_instruction * writer, 887bf215546Sopenharmony_ci struct rc_pair_sub_instruction * sub_writer, 888bf215546Sopenharmony_ci struct rc_reader_data * data, 889bf215546Sopenharmony_ci rc_read_src_fn read_normal_cb, 890bf215546Sopenharmony_ci rc_pair_read_arg_fn read_pair_cb, 891bf215546Sopenharmony_ci rc_read_write_mask_fn write_cb) 892bf215546Sopenharmony_ci{ 893bf215546Sopenharmony_ci struct get_readers_callback_data d; 894bf215546Sopenharmony_ci 895bf215546Sopenharmony_ci init_get_readers_callback_data(&d, data, c, read_normal_cb, 896bf215546Sopenharmony_ci read_pair_cb, write_cb); 897bf215546Sopenharmony_ci 898bf215546Sopenharmony_ci if (sub_writer->WriteMask) { 899bf215546Sopenharmony_ci get_readers_for_single_write(&d, writer, RC_FILE_TEMPORARY, 900bf215546Sopenharmony_ci sub_writer->DestIndex, sub_writer->WriteMask); 901bf215546Sopenharmony_ci } 902bf215546Sopenharmony_ci} 903