Path: blob/21.2-virgl/src/gallium/drivers/r300/compiler/radeon_dataflow_swizzles.c
4574 views
/*1* Copyright (C) 2009 Nicolai Haehnle.2* Copyright 2012 Advanced Micro Devices, Inc.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* Authors:27* Nicolai Haehnle28* Tom Stellard <[email protected]>29*/3031#include "radeon_dataflow.h"3233#include "radeon_code.h"34#include "radeon_compiler.h"35#include "radeon_compiler_util.h"36#include "radeon_swizzle.h"373839static void rewrite_source(struct radeon_compiler * c,40struct rc_instruction * inst, unsigned src)41{42struct rc_swizzle_split split;43unsigned int tempreg = rc_find_free_temporary(c);44unsigned int usemask;4546usemask = 0;47for(unsigned int chan = 0; chan < 4; ++chan) {48if (GET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan) != RC_SWIZZLE_UNUSED)49usemask |= 1 << chan;50}5152c->SwizzleCaps->Split(inst->U.I.SrcReg[src], usemask, &split);5354for(unsigned int phase = 0; phase < split.NumPhases; ++phase) {55struct rc_instruction * mov = rc_insert_new_instruction(c, inst->Prev);56unsigned int phase_refmask;57unsigned int masked_negate;5859mov->U.I.Opcode = RC_OPCODE_MOV;60mov->U.I.DstReg.File = RC_FILE_TEMPORARY;61mov->U.I.DstReg.Index = tempreg;62mov->U.I.DstReg.WriteMask = split.Phase[phase];63mov->U.I.SrcReg[0] = inst->U.I.SrcReg[src];64mov->U.I.PreSub = inst->U.I.PreSub;6566phase_refmask = 0;67for(unsigned int chan = 0; chan < 4; ++chan) {68if (!GET_BIT(split.Phase[phase], chan))69SET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan, RC_SWIZZLE_UNUSED);70else71phase_refmask |= 1 << GET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan);72}7374phase_refmask &= RC_MASK_XYZW;7576masked_negate = split.Phase[phase] & mov->U.I.SrcReg[0].Negate;77if (masked_negate == 0)78mov->U.I.SrcReg[0].Negate = 0;79else if (masked_negate == split.Phase[phase])80mov->U.I.SrcReg[0].Negate = RC_MASK_XYZW;8182}8384inst->U.I.SrcReg[src].File = RC_FILE_TEMPORARY;85inst->U.I.SrcReg[src].Index = tempreg;86inst->U.I.SrcReg[src].Swizzle = 0;87inst->U.I.SrcReg[src].Negate = RC_MASK_NONE;88inst->U.I.SrcReg[src].Abs = 0;89for(unsigned int chan = 0; chan < 4; ++chan) {90SET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan,91GET_BIT(usemask, chan) ? chan : RC_SWIZZLE_UNUSED);92}93}9495/**96* This function will attempt to rewrite non-native swizzles that read from97* immediate registers by rearranging the immediates to allow the98* instruction to use native swizzles.99*/100static unsigned try_rewrite_constant(struct radeon_compiler *c,101struct rc_src_register *reg)102{103unsigned new_swizzle, chan, swz0, swz1, swz2, swz3, found_swizzle, swz;104unsigned all_inline = 0;105float imms[4] = {0.0f, 0.0f, 0.0f, 0.0f};106107if (!rc_src_reg_is_immediate(c, reg->File, reg->Index)) {108/* The register does not contain immediates, but if all109* the swizzles are inline constants, we can still rewrite110* it. */111112new_swizzle = RC_SWIZZLE_XYZW;113for (chan = 0 ; chan < 4; chan++) {114unsigned swz = GET_SWZ(reg->Swizzle, chan);115if (swz <= RC_SWIZZLE_W) {116return 0;117}118if (swz == RC_SWIZZLE_UNUSED) {119SET_SWZ(new_swizzle, chan, RC_SWIZZLE_UNUSED);120}121}122all_inline = 1;123} else {124new_swizzle = reg->Swizzle;125}126127swz = RC_SWIZZLE_UNUSED;128found_swizzle = 1;129/* Check if all channels have the same swizzle. If they do we can skip130* the search for a native swizzle. We only need to check the first131* three channels, because any swizzle is legal in the fourth channel.132*/133for (chan = 0; chan < 3; chan++) {134unsigned chan_swz = GET_SWZ(reg->Swizzle, chan);135if (chan_swz == RC_SWIZZLE_UNUSED) {136continue;137}138if (swz == RC_SWIZZLE_UNUSED) {139swz = chan_swz;140} else if (swz != chan_swz) {141found_swizzle = 0;142break;143}144}145146/* Find a legal swizzle */147148/* This loop attempts to find a native swizzle where all the149* channels are different. */150while (!found_swizzle && !all_inline) {151swz0 = GET_SWZ(new_swizzle, 0);152swz1 = GET_SWZ(new_swizzle, 1);153swz2 = GET_SWZ(new_swizzle, 2);154155/* Swizzle .W. is never legal. */156if (swz1 == RC_SWIZZLE_W ||157swz1 == RC_SWIZZLE_UNUSED ||158swz1 == RC_SWIZZLE_ZERO ||159swz1 == RC_SWIZZLE_HALF ||160swz1 == RC_SWIZZLE_ONE) {161/* We chose Z, because there are two non-repeating162* swizzle combinations of the form .Z. There are163* only one combination each for .X. and .Y. */164SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);165continue;166}167168if (swz2 == RC_SWIZZLE_UNUSED) {169/* We choose Y, because there are two non-repeating170* swizzle combinations of the form ..Y */171SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);172continue;173}174175switch (swz0) {176/* X.. */177case RC_SWIZZLE_X:178/* Legal swizzles that start with X: XYZ, XXX */179switch (swz1) {180/* XX. */181case RC_SWIZZLE_X:182/* The new swizzle will be:183* ZXY (XX. => ZX. => ZXY) */184SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);185break;186/* XY. */187case RC_SWIZZLE_Y:188/* The new swizzle is XYZ */189SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Z);190found_swizzle = 1;191break;192/* XZ. */193case RC_SWIZZLE_Z:194/* XZZ */195if (swz2 == RC_SWIZZLE_Z) {196/* The new swizzle is XYZ */197SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Y);198found_swizzle = 1;199} else { /* XZ[^Z] */200/* The new swizzle will be:201* YZX (XZ. => YZ. => YZX) */202SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Y);203}204break;205/* XW. Should have already been handled. */206case RC_SWIZZLE_W:207assert(0);208break;209}210break;211/* Y.. */212case RC_SWIZZLE_Y:213/* Legal swizzles that start with Y: YYY, YZX */214switch (swz1) {215/* YY. */216case RC_SWIZZLE_Y:217/* The new swizzle will be:218* XYZ (YY. => XY. => XYZ) */219SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);220break;221/* YZ. */222case RC_SWIZZLE_Z:223/* The new swizzle is YZX */224SET_SWZ(new_swizzle, 2, RC_SWIZZLE_X);225found_swizzle = 1;226break;227/* YX. */228case RC_SWIZZLE_X:229/* YXX */230if (swz2 == RC_SWIZZLE_X) {231/*The new swizzle is YZX */232SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);233found_swizzle = 1;234} else { /* YX[^X] */235/* The new swizzle will be:236* ZXY (YX. => ZX. -> ZXY) */237SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);238}239break;240/* YW. Should have already been handled. */241case RC_SWIZZLE_W:242assert(0);243break;244}245break;246/* Z.. */247case RC_SWIZZLE_Z:248/* Legal swizzles that start with Z: ZZZ, ZXY */249switch (swz1) {250/* ZZ. */251case RC_SWIZZLE_Z:252/* The new swizzle will be:253* WZY (ZZ. => WZ. => WZY) */254SET_SWZ(new_swizzle, 0, RC_SWIZZLE_W);255break;256/* ZX. */257case RC_SWIZZLE_X:258/* The new swizzle is ZXY */259SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);260found_swizzle = 1;261break;262/* ZY. */263case RC_SWIZZLE_Y:264/* ZYY */265if (swz2 == RC_SWIZZLE_Y) {266/* The new swizzle is ZXY */267SET_SWZ(new_swizzle, 1, RC_SWIZZLE_X);268found_swizzle = 1;269} else { /* ZY[^Y] */270/* The new swizzle will be:271* XYZ (ZY. => XY. => XYZ) */272SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);273}274break;275/* ZW. Should have already been handled. */276case RC_SWIZZLE_W:277assert(0);278break;279}280break;281282/* W.. */283case RC_SWIZZLE_W:284/* Legal swizzles that start with X: WWW, WZY */285switch (swz1) {286/* WW. Should have already been handled. */287case RC_SWIZZLE_W:288assert(0);289break;290/* WZ. */291case RC_SWIZZLE_Z:292/* The new swizzle will be WZY */293SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);294found_swizzle = 1;295break;296/* WX. */297case RC_SWIZZLE_X:298/* WY. */299case RC_SWIZZLE_Y:300/* W[XY]Y */301if (swz2 == RC_SWIZZLE_Y) {302/* The new swizzle will be WZY */303SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);304found_swizzle = 1;305} else { /* W[XY][^Y] */306/* The new swizzle will be:307* ZXY (WX. => XX. => ZX. => ZXY) or308* XYZ (WY. => XY. => XYZ)309*/310SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);311}312break;313}314break;315/* U.. 0.. 1.. H..*/316case RC_SWIZZLE_UNUSED:317case RC_SWIZZLE_ZERO:318case RC_SWIZZLE_ONE:319case RC_SWIZZLE_HALF:320SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);321break;322}323}324325/* Handle the swizzle in the w channel. */326swz3 = GET_SWZ(reg->Swizzle, 3);327328/* We can skip this if the swizzle in channel w is an inline constant. */329if (swz3 <= RC_SWIZZLE_W) {330for (chan = 0; chan < 3; chan++) {331unsigned old_swz = GET_SWZ(reg->Swizzle, chan);332unsigned new_swz = GET_SWZ(new_swizzle, chan);333/* If the swizzle in the w channel is the same as the334* swizzle in any other channels, we need to rewrite it.335* For example:336* reg->Swizzle == XWZW337* new_swizzle == XYZX338* Since the swizzle in the y channel is being339* rewritten from W -> Y we need to change the swizzle340* in the w channel from W -> Y as well.341*/342if (old_swz == swz3) {343SET_SWZ(new_swizzle, 3,344GET_SWZ(new_swizzle, chan));345break;346}347348/* The swizzle in channel w will be overwritten by one349* of the new swizzles. */350if (new_swz == swz3) {351/* Find an unused swizzle */352unsigned i;353unsigned used = 0;354for (i = 0; i < 3; i++) {355used |= 1 << GET_SWZ(new_swizzle, i);356}357for (i = 0; i < 4; i++) {358if (used & (1 << i)) {359continue;360}361SET_SWZ(new_swizzle, 3, i);362}363}364}365}366367for (chan = 0; chan < 4; chan++) {368unsigned old_swz = GET_SWZ(reg->Swizzle, chan);369unsigned new_swz = GET_SWZ(new_swizzle, chan);370371if (old_swz == RC_SWIZZLE_UNUSED) {372continue;373}374375/* We don't need to change the swizzle in channel w if it is376* an inline constant. These are always legal in the w channel.377*378* Swizzles with a value > RC_SWIZZLE_W are inline constants.379*/380if (chan == 3 && old_swz > RC_SWIZZLE_W) {381continue;382}383384assert(new_swz <= RC_SWIZZLE_W);385386switch (old_swz) {387case RC_SWIZZLE_ZERO:388imms[new_swz] = 0.0f;389break;390case RC_SWIZZLE_HALF:391if (reg->Negate & (1 << chan)) {392imms[new_swz] = -0.5f;393} else {394imms[new_swz] = 0.5f;395}396break;397case RC_SWIZZLE_ONE:398if (reg->Negate & (1 << chan)) {399imms[new_swz] = -1.0f;400} else {401imms[new_swz] = 1.0f;402}403break;404default:405imms[new_swz] = rc_get_constant_value(c, reg->Index,406reg->Swizzle, reg->Negate, chan);407}408SET_SWZ(reg->Swizzle, chan, new_swz);409}410reg->Index = rc_constants_add_immediate_vec4(&c->Program.Constants,411imms);412/* We need to set the register file to CONSTANT in case we are413* converting a non-constant register with constant swizzles (e.g.414* ONE, ZERO, HALF).415*/416reg->File = RC_FILE_CONSTANT;417reg->Negate = 0;418return 1;419}420421void rc_dataflow_swizzles(struct radeon_compiler * c, void *user)422{423struct rc_instruction * inst;424425for(inst = c->Program.Instructions.Next;426inst != &c->Program.Instructions;427inst = inst->Next) {428const struct rc_opcode_info * opcode =429rc_get_opcode_info(inst->U.I.Opcode);430unsigned int src;431432for(src = 0; src < opcode->NumSrcRegs; ++src) {433struct rc_src_register *reg = &inst->U.I.SrcReg[src];434if (c->SwizzleCaps->IsNative(inst->U.I.Opcode, *reg)) {435continue;436}437if (!c->is_r500 &&438c->Program.Constants.Count < R300_PFS_NUM_CONST_REGS &&439try_rewrite_constant(c, reg)) {440continue;441}442rewrite_source(c, inst, src);443}444}445if (c->Debug & RC_DBG_LOG)446rc_constants_print(&c->Program.Constants);447}448449450