Path: blob/21.2-virgl/src/gallium/drivers/r300/compiler/radeon_dataflow.c
4574 views
/*1* Copyright (C) 2009 Nicolai Haehnle.2* Copyright 2010 Tom Stellard <[email protected]>3*4* All Rights Reserved.5*6* Permission is hereby granted, free of charge, to any person obtaining7* a copy of this software and associated documentation files (the8* "Software"), to deal in the Software without restriction, including9* without limitation the rights to use, copy, modify, merge, publish,10* distribute, sublicense, and/or sell copies of the Software, and to11* permit persons to whom the Software is furnished to do so, subject to12* the following conditions:13*14* The above copyright notice and this permission notice (including the15* next paragraph) shall be included in all copies or substantial16* portions of the Software.17*18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,19* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF20* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.21* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE22* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION23* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION24* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.25*26*/2728#include "radeon_dataflow.h"2930#include "radeon_compiler.h"31#include "radeon_compiler_util.h"32#include "radeon_program.h"3334struct read_write_mask_data {35void * UserData;36rc_read_write_mask_fn Cb;37};3839static void reads_normal_callback(40void * userdata,41struct rc_instruction * fullinst,42struct rc_src_register * src)43{44struct read_write_mask_data * cb_data = userdata;45unsigned int refmask = 0;46unsigned int chan;47for(chan = 0; chan < 4; chan++) {48refmask |= 1 << GET_SWZ(src->Swizzle, chan);49}50refmask &= RC_MASK_XYZW;5152if (refmask) {53cb_data->Cb(cb_data->UserData, fullinst, src->File,54src->Index, refmask);55}5657if (refmask && src->RelAddr) {58cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0,59RC_MASK_X);60}61}6263static void pair_get_src_refmasks(unsigned int * refmasks,64struct rc_pair_instruction * inst,65unsigned int swz, unsigned int src)66{67if (swz >= 4)68return;6970if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) {71if(src == RC_PAIR_PRESUB_SRC) {72unsigned int i;73int srcp_regs =74rc_presubtract_src_reg_count(75inst->RGB.Src[src].Index);76for(i = 0; i < srcp_regs; i++) {77refmasks[i] |= 1 << swz;78}79}80else {81refmasks[src] |= 1 << swz;82}83}8485if (swz == RC_SWIZZLE_W) {86if (src == RC_PAIR_PRESUB_SRC) {87unsigned int i;88int srcp_regs = rc_presubtract_src_reg_count(89inst->Alpha.Src[src].Index);90for(i = 0; i < srcp_regs; i++) {91refmasks[i] |= 1 << swz;92}93}94else {95refmasks[src] |= 1 << swz;96}97}98}99100static void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)101{102struct rc_pair_instruction * inst = &fullinst->U.P;103unsigned int refmasks[3] = { 0, 0, 0 };104105unsigned int arg;106107for(arg = 0; arg < 3; ++arg) {108unsigned int chan;109for(chan = 0; chan < 3; ++chan) {110unsigned int swz_rgb =111GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan);112unsigned int swz_alpha =113GET_SWZ(inst->Alpha.Arg[arg].Swizzle, chan);114pair_get_src_refmasks(refmasks, inst, swz_rgb,115inst->RGB.Arg[arg].Source);116pair_get_src_refmasks(refmasks, inst, swz_alpha,117inst->Alpha.Arg[arg].Source);118}119}120121for(unsigned int src = 0; src < 3; ++src) {122if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ))123cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index,124refmasks[src] & RC_MASK_XYZ);125126if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W))127cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W);128}129}130131static void pair_sub_for_all_args(132struct rc_instruction * fullinst,133struct rc_pair_sub_instruction * sub,134rc_pair_read_arg_fn cb,135void * userdata)136{137int i;138const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);139140for(i = 0; i < info->NumSrcRegs; i++) {141unsigned int src_type;142143src_type = rc_source_type_swz(sub->Arg[i].Swizzle);144145if (src_type == RC_SOURCE_NONE)146continue;147148if (sub->Arg[i].Source == RC_PAIR_PRESUB_SRC) {149unsigned int presub_type;150unsigned int presub_src_count;151struct rc_pair_instruction_source * src_array;152unsigned int j;153154if (src_type & RC_SOURCE_RGB) {155presub_type = fullinst->156U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index;157src_array = fullinst->U.P.RGB.Src;158} else {159presub_type = fullinst->160U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index;161src_array = fullinst->U.P.Alpha.Src;162}163presub_src_count164= rc_presubtract_src_reg_count(presub_type);165for(j = 0; j < presub_src_count; j++) {166cb(userdata, fullinst, &sub->Arg[i],167&src_array[j]);168}169} else {170struct rc_pair_instruction_source * src =171rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]);172if (src) {173cb(userdata, fullinst, &sub->Arg[i], src);174}175}176}177}178179/* This function calls the callback function (cb) for each source used by180* the instruction.181* */182void rc_for_all_reads_src(183struct rc_instruction * inst,184rc_read_src_fn cb,185void * userdata)186{187const struct rc_opcode_info * opcode =188rc_get_opcode_info(inst->U.I.Opcode);189190/* This function only works with normal instructions. */191if (inst->Type != RC_INSTRUCTION_NORMAL) {192assert(0);193return;194}195196for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {197198if (inst->U.I.SrcReg[src].File == RC_FILE_NONE)199continue;200201if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) {202unsigned int i;203unsigned int srcp_regs = rc_presubtract_src_reg_count(204inst->U.I.PreSub.Opcode);205for( i = 0; i < srcp_regs; i++) {206cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]);207}208} else {209cb(userdata, inst, &inst->U.I.SrcReg[src]);210}211}212}213214/**215* This function calls the callback function (cb) for each arg of the RGB and216* alpha components.217*/218void rc_pair_for_all_reads_arg(219struct rc_instruction * inst,220rc_pair_read_arg_fn cb,221void * userdata)222{223/* This function only works with pair instructions. */224if (inst->Type != RC_INSTRUCTION_PAIR) {225assert(0);226return;227}228229pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata);230pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata);231}232233/**234* Calls a callback function for all register reads.235*236* This is conservative, i.e. if the same register is referenced multiple times,237* the callback may also be called multiple times.238* Also, the writemask of the instruction is not taken into account.239*/240void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)241{242if (inst->Type == RC_INSTRUCTION_NORMAL) {243struct read_write_mask_data cb_data;244cb_data.UserData = userdata;245cb_data.Cb = cb;246247rc_for_all_reads_src(inst, reads_normal_callback, &cb_data);248} else {249reads_pair(inst, cb, userdata);250}251}252253254255static void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)256{257struct rc_sub_instruction * inst = &fullinst->U.I;258const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);259260if (opcode->HasDstReg && inst->DstReg.WriteMask)261cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask);262263if (inst->WriteALUResult)264cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);265}266267static void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)268{269struct rc_pair_instruction * inst = &fullinst->U.P;270271if (inst->RGB.WriteMask)272cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask);273274if (inst->Alpha.WriteMask)275cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W);276277if (inst->WriteALUResult)278cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);279}280281/**282* Calls a callback function for all register writes in the instruction,283* reporting writemasks to the callback function.284*285* \warning Does not report output registers for paired instructions!286*/287void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)288{289if (inst->Type == RC_INSTRUCTION_NORMAL) {290writes_normal(inst, cb, userdata);291} else {292writes_pair(inst, cb, userdata);293}294}295296297struct mask_to_chan_data {298void * UserData;299rc_read_write_chan_fn Fn;300};301302static void mask_to_chan_cb(void * data, struct rc_instruction * inst,303rc_register_file file, unsigned int index, unsigned int mask)304{305struct mask_to_chan_data * d = data;306for(unsigned int chan = 0; chan < 4; ++chan) {307if (GET_BIT(mask, chan))308d->Fn(d->UserData, inst, file, index, chan);309}310}311312/**313* Calls a callback function for all sourced register channels.314*315* This is conservative, i.e. channels may be called multiple times,316* and the writemask of the instruction is not taken into account.317*/318void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)319{320struct mask_to_chan_data d;321d.UserData = userdata;322d.Fn = cb;323rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d);324}325326/**327* Calls a callback function for all written register channels.328*329* \warning Does not report output registers for paired instructions!330*/331void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)332{333struct mask_to_chan_data d;334d.UserData = userdata;335d.Fn = cb;336rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d);337}338339static void remap_normal_instruction(struct rc_instruction * fullinst,340rc_remap_register_fn cb, void * userdata)341{342struct rc_sub_instruction * inst = &fullinst->U.I;343const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);344unsigned int remapped_presub = 0;345346if (opcode->HasDstReg) {347rc_register_file file = inst->DstReg.File;348unsigned int index = inst->DstReg.Index;349350cb(userdata, fullinst, &file, &index);351352inst->DstReg.File = file;353inst->DstReg.Index = index;354}355356for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {357rc_register_file file = inst->SrcReg[src].File;358unsigned int index = inst->SrcReg[src].Index;359360if (file == RC_FILE_PRESUB) {361unsigned int i;362unsigned int srcp_srcs = rc_presubtract_src_reg_count(363inst->PreSub.Opcode);364/* Make sure we only remap presubtract sources once in365* case more than one source register reads the366* presubtract result. */367if (remapped_presub)368continue;369370for(i = 0; i < srcp_srcs; i++) {371file = inst->PreSub.SrcReg[i].File;372index = inst->PreSub.SrcReg[i].Index;373cb(userdata, fullinst, &file, &index);374inst->PreSub.SrcReg[i].File = file;375inst->PreSub.SrcReg[i].Index = index;376}377remapped_presub = 1;378}379else {380cb(userdata, fullinst, &file, &index);381382inst->SrcReg[src].File = file;383inst->SrcReg[src].Index = index;384}385}386}387388static void remap_pair_instruction(struct rc_instruction * fullinst,389rc_remap_register_fn cb, void * userdata)390{391struct rc_pair_instruction * inst = &fullinst->U.P;392393if (inst->RGB.WriteMask) {394rc_register_file file = RC_FILE_TEMPORARY;395unsigned int index = inst->RGB.DestIndex;396397cb(userdata, fullinst, &file, &index);398399inst->RGB.DestIndex = index;400}401402if (inst->Alpha.WriteMask) {403rc_register_file file = RC_FILE_TEMPORARY;404unsigned int index = inst->Alpha.DestIndex;405406cb(userdata, fullinst, &file, &index);407408inst->Alpha.DestIndex = index;409}410411for(unsigned int src = 0; src < 3; ++src) {412if (inst->RGB.Src[src].Used) {413rc_register_file file = inst->RGB.Src[src].File;414unsigned int index = inst->RGB.Src[src].Index;415416cb(userdata, fullinst, &file, &index);417418inst->RGB.Src[src].File = file;419inst->RGB.Src[src].Index = index;420}421422if (inst->Alpha.Src[src].Used) {423rc_register_file file = inst->Alpha.Src[src].File;424unsigned int index = inst->Alpha.Src[src].Index;425426cb(userdata, fullinst, &file, &index);427428inst->Alpha.Src[src].File = file;429inst->Alpha.Src[src].Index = index;430}431}432}433434435/**436* Remap all register accesses according to the given function.437* That is, call the function \p cb for each referenced register (both read and written)438* and update the given instruction \p inst accordingly439* if it modifies its \ref pfile and \ref pindex contents.440*/441void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata)442{443if (inst->Type == RC_INSTRUCTION_NORMAL)444remap_normal_instruction(inst, cb, userdata);445else446remap_pair_instruction(inst, cb, userdata);447}448449struct branch_write_mask {450unsigned int IfWriteMask:4;451unsigned int ElseWriteMask:4;452unsigned int HasElse:1;453};454455union get_readers_read_cb {456rc_read_src_fn I;457rc_pair_read_arg_fn P;458};459460struct get_readers_callback_data {461struct radeon_compiler * C;462struct rc_reader_data * ReaderData;463rc_read_src_fn ReadNormalCB;464rc_pair_read_arg_fn ReadPairCB;465rc_read_write_mask_fn WriteCB;466rc_register_file DstFile;467unsigned int DstIndex;468unsigned int DstMask;469unsigned int AliveWriteMask;470/* For convenience, this is indexed starting at 1 */471struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1];472};473474static struct rc_reader * add_reader(475struct memory_pool * pool,476struct rc_reader_data * data,477struct rc_instruction * inst,478unsigned int mask)479{480struct rc_reader * new;481memory_pool_array_reserve(pool, struct rc_reader, data->Readers,482data->ReaderCount, data->ReadersReserved, 1);483new = &data->Readers[data->ReaderCount++];484new->Inst = inst;485new->WriteMask = mask;486return new;487}488489static void add_reader_normal(490struct memory_pool * pool,491struct rc_reader_data * data,492struct rc_instruction * inst,493unsigned int mask,494struct rc_src_register * src)495{496struct rc_reader * new = add_reader(pool, data, inst, mask);497new->U.I.Src = src;498}499500501static void add_reader_pair(502struct memory_pool * pool,503struct rc_reader_data * data,504struct rc_instruction * inst,505unsigned int mask,506struct rc_pair_instruction_arg * arg,507struct rc_pair_instruction_source * src)508{509struct rc_reader * new = add_reader(pool, data, inst, mask);510new->U.P.Src = src;511new->U.P.Arg = arg;512}513514static unsigned int get_readers_read_callback(515struct get_readers_callback_data * cb_data,516unsigned int has_rel_addr,517rc_register_file file,518unsigned int index,519unsigned int swizzle)520{521unsigned int shared_mask, read_mask;522523if (has_rel_addr) {524cb_data->ReaderData->Abort = 1;525return RC_MASK_NONE;526}527528shared_mask = rc_src_reads_dst_mask(file, index, swizzle,529cb_data->DstFile, cb_data->DstIndex, cb_data->AliveWriteMask);530531if (shared_mask == RC_MASK_NONE)532return shared_mask;533534/* If we make it this far, it means that this source reads from the535* same register written to by d->ReaderData->Writer. */536537read_mask = rc_swizzle_to_writemask(swizzle);538if (cb_data->ReaderData->AbortOnRead & read_mask) {539cb_data->ReaderData->Abort = 1;540return shared_mask;541}542543if (cb_data->ReaderData->LoopDepth > 0) {544cb_data->ReaderData->AbortOnWrite |=545(read_mask & cb_data->AliveWriteMask);546}547548/* XXX The behavior in this case should be configurable. */549if ((read_mask & cb_data->AliveWriteMask) != read_mask) {550cb_data->ReaderData->Abort = 1;551return shared_mask;552}553554return shared_mask;555}556557static void get_readers_pair_read_callback(558void * userdata,559struct rc_instruction * inst,560struct rc_pair_instruction_arg * arg,561struct rc_pair_instruction_source * src)562{563unsigned int shared_mask;564struct get_readers_callback_data * d = userdata;565566shared_mask = get_readers_read_callback(d,5670 /*Pair Instructions don't use RelAddr*/,568src->File, src->Index, arg->Swizzle);569570if (shared_mask == RC_MASK_NONE)571return;572573if (d->ReadPairCB)574d->ReadPairCB(d->ReaderData, inst, arg, src);575576if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)577return;578579add_reader_pair(&d->C->Pool, d->ReaderData, inst, shared_mask, arg, src);580}581582/**583* This function is used by rc_get_readers_normal() to determine whether inst584* is a reader of userdata->ReaderData->Writer585*/586static void get_readers_normal_read_callback(587void * userdata,588struct rc_instruction * inst,589struct rc_src_register * src)590{591struct get_readers_callback_data * d = userdata;592unsigned int shared_mask;593594shared_mask = get_readers_read_callback(d,595src->RelAddr, src->File, src->Index, src->Swizzle);596597if (shared_mask == RC_MASK_NONE)598return;599/* The callback function could potentially clear d->ReaderData->Abort,600* so we need to call it before we return. */601if (d->ReadNormalCB)602d->ReadNormalCB(d->ReaderData, inst, src);603604if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)605return;606607add_reader_normal(&d->C->Pool, d->ReaderData, inst, shared_mask, src);608}609610/**611* This function is used by rc_get_readers_normal() to determine when612* userdata->ReaderData->Writer is dead (i. e. All components of its613* destination register have been overwritten by other instructions).614*/615static void get_readers_write_callback(616void *userdata,617struct rc_instruction * inst,618rc_register_file file,619unsigned int index,620unsigned int mask)621{622struct get_readers_callback_data * d = userdata;623624if (index == d->DstIndex && file == d->DstFile) {625unsigned int shared_mask = mask & d->DstMask;626d->ReaderData->AbortOnRead &= ~shared_mask;627d->AliveWriteMask &= ~shared_mask;628if (d->ReaderData->AbortOnWrite & shared_mask) {629d->ReaderData->Abort = 1;630}631}632633if(d->WriteCB)634d->WriteCB(d->ReaderData, inst, file, index, mask);635}636637static void push_branch_mask(638struct get_readers_callback_data * d,639unsigned int * branch_depth)640{641(*branch_depth)++;642if (*branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) {643d->ReaderData->Abort = 1;644return;645}646d->BranchMasks[*branch_depth].IfWriteMask =647d->AliveWriteMask;648}649650static void pop_branch_mask(651struct get_readers_callback_data * d,652unsigned int * branch_depth)653{654struct branch_write_mask * masks = &d->BranchMasks[*branch_depth];655656if (masks->HasElse) {657/* Abort on read for components that were written in the IF658* block. */659d->ReaderData->AbortOnRead |=660masks->IfWriteMask & ~masks->ElseWriteMask;661/* Abort on read for components that were written in the ELSE662* block. */663d->ReaderData->AbortOnRead |=664masks->ElseWriteMask & ~d->AliveWriteMask;665666d->AliveWriteMask = masks->IfWriteMask667^ ((masks->IfWriteMask ^ masks->ElseWriteMask)668& (masks->IfWriteMask ^ d->AliveWriteMask));669} else {670d->ReaderData->AbortOnRead |=671masks->IfWriteMask & ~d->AliveWriteMask;672d->AliveWriteMask = masks->IfWriteMask;673674}675memset(masks, 0, sizeof(struct branch_write_mask));676(*branch_depth)--;677}678679static void get_readers_for_single_write(680void * userdata,681struct rc_instruction * writer,682rc_register_file dst_file,683unsigned int dst_index,684unsigned int dst_mask)685{686struct rc_instruction * tmp;687unsigned int branch_depth = 0;688struct rc_instruction * endloop = NULL;689unsigned int abort_on_read_at_endloop = 0;690struct get_readers_callback_data * d = userdata;691692d->ReaderData->Writer = writer;693d->ReaderData->AbortOnRead = 0;694d->ReaderData->AbortOnWrite = 0;695d->ReaderData->LoopDepth = 0;696d->ReaderData->InElse = 0;697d->DstFile = dst_file;698d->DstIndex = dst_index;699d->DstMask = dst_mask;700d->AliveWriteMask = dst_mask;701memset(d->BranchMasks, 0, sizeof(d->BranchMasks));702703if (!dst_mask)704return;705706for(tmp = writer->Next; tmp != &d->C->Program.Instructions;707tmp = tmp->Next){708rc_opcode opcode = rc_get_flow_control_inst(tmp);709switch(opcode) {710case RC_OPCODE_BGNLOOP:711d->ReaderData->LoopDepth++;712push_branch_mask(d, &branch_depth);713break;714case RC_OPCODE_ENDLOOP:715if (d->ReaderData->LoopDepth > 0) {716d->ReaderData->LoopDepth--;717if (d->ReaderData->LoopDepth == 0) {718d->ReaderData->AbortOnWrite = 0;719}720pop_branch_mask(d, &branch_depth);721} else {722/* Here we have reached an ENDLOOP without723* seeing its BGNLOOP. These means that724* the writer was written inside of a loop,725* so it could have readers that are above it726* (i.e. they have a lower IP). To find these727* readers we jump to the BGNLOOP instruction728* and check each instruction until we get729* back to the writer.730*/731endloop = tmp;732tmp = rc_match_endloop(tmp);733if (!tmp) {734rc_error(d->C, "Failed to match endloop.\n");735d->ReaderData->Abort = 1;736return;737}738abort_on_read_at_endloop = d->ReaderData->AbortOnRead;739d->ReaderData->AbortOnRead |= d->AliveWriteMask;740continue;741}742break;743case RC_OPCODE_IF:744push_branch_mask(d, &branch_depth);745break;746case RC_OPCODE_ELSE:747if (branch_depth == 0) {748d->ReaderData->InElse = 1;749} else {750unsigned int temp_mask = d->AliveWriteMask;751d->AliveWriteMask =752d->BranchMasks[branch_depth].IfWriteMask;753d->BranchMasks[branch_depth].ElseWriteMask =754temp_mask;755d->BranchMasks[branch_depth].HasElse = 1;756}757break;758case RC_OPCODE_ENDIF:759if (branch_depth == 0) {760d->ReaderData->AbortOnRead = d->AliveWriteMask;761d->ReaderData->InElse = 0;762}763else {764pop_branch_mask(d, &branch_depth);765}766break;767default:768break;769}770771if (d->ReaderData->InElse)772continue;773774if (tmp->Type == RC_INSTRUCTION_NORMAL) {775rc_for_all_reads_src(tmp,776get_readers_normal_read_callback, d);777} else {778rc_pair_for_all_reads_arg(tmp,779get_readers_pair_read_callback, d);780}781782/* This can happen when we jump from an ENDLOOP to BGNLOOP */783if (tmp == writer) {784tmp = endloop;785endloop = NULL;786d->ReaderData->AbortOnRead = abort_on_read_at_endloop;787continue;788}789rc_for_all_writes_mask(tmp, get_readers_write_callback, d);790791if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)792return;793794if (branch_depth == 0 && !d->AliveWriteMask)795return;796}797}798799static void init_get_readers_callback_data(800struct get_readers_callback_data * d,801struct rc_reader_data * reader_data,802struct radeon_compiler * c,803rc_read_src_fn read_normal_cb,804rc_pair_read_arg_fn read_pair_cb,805rc_read_write_mask_fn write_cb)806{807reader_data->Abort = 0;808reader_data->ReaderCount = 0;809reader_data->ReadersReserved = 0;810reader_data->Readers = NULL;811812d->C = c;813d->ReaderData = reader_data;814d->ReadNormalCB = read_normal_cb;815d->ReadPairCB = read_pair_cb;816d->WriteCB = write_cb;817}818819/**820* This function will create a list of readers via the rc_reader_data struct.821* This function will abort (set the flag data->Abort) and return if it822* encounters an instruction that reads from @param writer and also a different823* instruction. Here are some examples:824*825* writer = instruction 0;826* 0 MOV TEMP[0].xy, TEMP[1].xy827* 1 MOV TEMP[0].zw, TEMP[2].xy828* 2 MOV TEMP[3], TEMP[0]829* The Abort flag will be set on instruction 2, because it reads values written830* by instructions 0 and 1.831*832* writer = instruction 1;833* 0 IF TEMP[0].x834* 1 MOV TEMP[1], TEMP[2]835* 2 ELSE836* 3 MOV TEMP[1], TEMP[2]837* 4 ENDIF838* 5 MOV TEMP[3], TEMP[1]839* The Abort flag will be set on instruction 5, because it could read from the840* value written by either instruction 1 or 3, depending on the jump decision841* made at instruction 0.842*843* writer = instruction 0;844* 0 MOV TEMP[0], TEMP[1]845* 2 BGNLOOP846* 3 ADD TEMP[0], TEMP[0], none.1847* 4 ENDLOOP848* The Abort flag will be set on instruction 3, because in the first iteration849* of the loop it reads the value written by instruction 0 and in all other850* iterations it reads the value written by instruction 3.851*852* @param read_cb This function will be called for every instruction that853* has been determined to be a reader of writer.854* @param write_cb This function will be called for every instruction after855* writer.856*/857void rc_get_readers(858struct radeon_compiler * c,859struct rc_instruction * writer,860struct rc_reader_data * data,861rc_read_src_fn read_normal_cb,862rc_pair_read_arg_fn read_pair_cb,863rc_read_write_mask_fn write_cb)864{865struct get_readers_callback_data d;866867init_get_readers_callback_data(&d, data, c, read_normal_cb,868read_pair_cb, write_cb);869870rc_for_all_writes_mask(writer, get_readers_for_single_write, &d);871}872873void rc_get_readers_sub(874struct radeon_compiler * c,875struct rc_instruction * writer,876struct rc_pair_sub_instruction * sub_writer,877struct rc_reader_data * data,878rc_read_src_fn read_normal_cb,879rc_pair_read_arg_fn read_pair_cb,880rc_read_write_mask_fn write_cb)881{882struct get_readers_callback_data d;883884init_get_readers_callback_data(&d, data, c, read_normal_cb,885read_pair_cb, write_cb);886887if (sub_writer->WriteMask) {888get_readers_for_single_write(&d, writer, RC_FILE_TEMPORARY,889sub_writer->DestIndex, sub_writer->WriteMask);890}891}892893894