1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com> 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci#include "radeon_compiler.h" 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci#include <stdbool.h> 26bf215546Sopenharmony_ci#include <stdio.h> 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "r300_reg.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include "radeon_compiler_util.h" 31bf215546Sopenharmony_ci#include "radeon_dataflow.h" 32bf215546Sopenharmony_ci#include "radeon_program.h" 33bf215546Sopenharmony_ci#include "radeon_program_alu.h" 34bf215546Sopenharmony_ci#include "radeon_swizzle.h" 35bf215546Sopenharmony_ci#include "radeon_emulate_branches.h" 36bf215546Sopenharmony_ci#include "radeon_remove_constants.h" 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci#include "util/compiler.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci/* 41bf215546Sopenharmony_ci * Take an already-setup and valid source then swizzle it appropriately to 42bf215546Sopenharmony_ci * obtain a constant ZERO or ONE source. 43bf215546Sopenharmony_ci */ 44bf215546Sopenharmony_ci#define __CONST(x, y) \ 45bf215546Sopenharmony_ci (PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[x]), \ 46bf215546Sopenharmony_ci t_swizzle(y), \ 47bf215546Sopenharmony_ci t_swizzle(y), \ 48bf215546Sopenharmony_ci t_swizzle(y), \ 49bf215546Sopenharmony_ci t_swizzle(y), \ 50bf215546Sopenharmony_ci t_src_class(vpi->SrcReg[x].File), \ 51bf215546Sopenharmony_ci RC_MASK_NONE) | (vpi->SrcReg[x].RelAddr << 4)) 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic unsigned long t_dst_mask(unsigned int mask) 55bf215546Sopenharmony_ci{ 56bf215546Sopenharmony_ci /* RC_MASK_* is equivalent to VSF_FLAG_* */ 57bf215546Sopenharmony_ci return mask & RC_MASK_XYZW; 58bf215546Sopenharmony_ci} 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_cistatic unsigned long t_dst_class(rc_register_file file) 61bf215546Sopenharmony_ci{ 62bf215546Sopenharmony_ci switch (file) { 63bf215546Sopenharmony_ci default: 64bf215546Sopenharmony_ci fprintf(stderr, "%s: Bad register file %i\n", __FUNCTION__, file); 65bf215546Sopenharmony_ci FALLTHROUGH; 66bf215546Sopenharmony_ci case RC_FILE_TEMPORARY: 67bf215546Sopenharmony_ci return PVS_DST_REG_TEMPORARY; 68bf215546Sopenharmony_ci case RC_FILE_OUTPUT: 69bf215546Sopenharmony_ci return PVS_DST_REG_OUT; 70bf215546Sopenharmony_ci case RC_FILE_ADDRESS: 71bf215546Sopenharmony_ci return PVS_DST_REG_A0; 72bf215546Sopenharmony_ci } 73bf215546Sopenharmony_ci} 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_cistatic unsigned long t_dst_index(struct r300_vertex_program_code *vp, 76bf215546Sopenharmony_ci struct rc_dst_register *dst) 77bf215546Sopenharmony_ci{ 78bf215546Sopenharmony_ci if (dst->File == RC_FILE_OUTPUT) 79bf215546Sopenharmony_ci return vp->outputs[dst->Index]; 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci return dst->Index; 82bf215546Sopenharmony_ci} 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_cistatic unsigned long t_src_class(rc_register_file file) 85bf215546Sopenharmony_ci{ 86bf215546Sopenharmony_ci switch (file) { 87bf215546Sopenharmony_ci default: 88bf215546Sopenharmony_ci fprintf(stderr, "%s: Bad register file %i\n", __FUNCTION__, file); 89bf215546Sopenharmony_ci FALLTHROUGH; 90bf215546Sopenharmony_ci case RC_FILE_NONE: 91bf215546Sopenharmony_ci case RC_FILE_TEMPORARY: 92bf215546Sopenharmony_ci return PVS_SRC_REG_TEMPORARY; 93bf215546Sopenharmony_ci case RC_FILE_INPUT: 94bf215546Sopenharmony_ci return PVS_SRC_REG_INPUT; 95bf215546Sopenharmony_ci case RC_FILE_CONSTANT: 96bf215546Sopenharmony_ci return PVS_SRC_REG_CONSTANT; 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci} 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_cistatic int t_src_conflict(struct rc_src_register a, struct rc_src_register b) 101bf215546Sopenharmony_ci{ 102bf215546Sopenharmony_ci unsigned long aclass = t_src_class(a.File); 103bf215546Sopenharmony_ci unsigned long bclass = t_src_class(b.File); 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci if (aclass != bclass) 106bf215546Sopenharmony_ci return 0; 107bf215546Sopenharmony_ci if (aclass == PVS_SRC_REG_TEMPORARY) 108bf215546Sopenharmony_ci return 0; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci if (a.RelAddr || b.RelAddr) 111bf215546Sopenharmony_ci return 1; 112bf215546Sopenharmony_ci if (a.Index != b.Index) 113bf215546Sopenharmony_ci return 1; 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci return 0; 116bf215546Sopenharmony_ci} 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_cistatic inline unsigned long t_swizzle(unsigned int swizzle) 119bf215546Sopenharmony_ci{ 120bf215546Sopenharmony_ci /* this is in fact a NOP as the Mesa RC_SWIZZLE_* are all identical to VSF_IN_COMPONENT_* */ 121bf215546Sopenharmony_ci return swizzle; 122bf215546Sopenharmony_ci} 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_cistatic unsigned long t_src_index(struct r300_vertex_program_code *vp, 125bf215546Sopenharmony_ci struct rc_src_register *src) 126bf215546Sopenharmony_ci{ 127bf215546Sopenharmony_ci if (src->File == RC_FILE_INPUT) { 128bf215546Sopenharmony_ci assert(vp->inputs[src->Index] != -1); 129bf215546Sopenharmony_ci return vp->inputs[src->Index]; 130bf215546Sopenharmony_ci } else { 131bf215546Sopenharmony_ci if (src->Index < 0) { 132bf215546Sopenharmony_ci fprintf(stderr, 133bf215546Sopenharmony_ci "negative offsets for indirect addressing do not work.\n"); 134bf215546Sopenharmony_ci return 0; 135bf215546Sopenharmony_ci } 136bf215546Sopenharmony_ci return src->Index; 137bf215546Sopenharmony_ci } 138bf215546Sopenharmony_ci} 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci/* these two functions should probably be merged... */ 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_cistatic unsigned long t_src(struct r300_vertex_program_code *vp, 143bf215546Sopenharmony_ci struct rc_src_register *src) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci /* src->Negate uses the RC_MASK_ flags from program_instruction.h, 146bf215546Sopenharmony_ci * which equal our VSF_FLAGS_ values, so it's safe to just pass it here. 147bf215546Sopenharmony_ci */ 148bf215546Sopenharmony_ci return PVS_SRC_OPERAND(t_src_index(vp, src), 149bf215546Sopenharmony_ci t_swizzle(GET_SWZ(src->Swizzle, 0)), 150bf215546Sopenharmony_ci t_swizzle(GET_SWZ(src->Swizzle, 1)), 151bf215546Sopenharmony_ci t_swizzle(GET_SWZ(src->Swizzle, 2)), 152bf215546Sopenharmony_ci t_swizzle(GET_SWZ(src->Swizzle, 3)), 153bf215546Sopenharmony_ci t_src_class(src->File), 154bf215546Sopenharmony_ci src->Negate) | 155bf215546Sopenharmony_ci (src->RelAddr << 4) | (src->Abs << 3); 156bf215546Sopenharmony_ci} 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_cistatic unsigned long t_src_scalar(struct r300_vertex_program_code *vp, 159bf215546Sopenharmony_ci struct rc_src_register *src) 160bf215546Sopenharmony_ci{ 161bf215546Sopenharmony_ci /* src->Negate uses the RC_MASK_ flags from program_instruction.h, 162bf215546Sopenharmony_ci * which equal our VSF_FLAGS_ values, so it's safe to just pass it here. 163bf215546Sopenharmony_ci */ 164bf215546Sopenharmony_ci unsigned int swz = rc_get_scalar_src_swz(src->Swizzle); 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci return PVS_SRC_OPERAND(t_src_index(vp, src), 167bf215546Sopenharmony_ci t_swizzle(swz), 168bf215546Sopenharmony_ci t_swizzle(swz), 169bf215546Sopenharmony_ci t_swizzle(swz), 170bf215546Sopenharmony_ci t_swizzle(swz), 171bf215546Sopenharmony_ci t_src_class(src->File), 172bf215546Sopenharmony_ci src->Negate ? RC_MASK_XYZW : RC_MASK_NONE) | 173bf215546Sopenharmony_ci (src->RelAddr << 4) | (src->Abs << 3); 174bf215546Sopenharmony_ci} 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_cistatic int valid_dst(struct r300_vertex_program_code *vp, 177bf215546Sopenharmony_ci struct rc_dst_register *dst) 178bf215546Sopenharmony_ci{ 179bf215546Sopenharmony_ci if (dst->File == RC_FILE_OUTPUT && vp->outputs[dst->Index] == -1) { 180bf215546Sopenharmony_ci return 0; 181bf215546Sopenharmony_ci } else if (dst->File == RC_FILE_ADDRESS) { 182bf215546Sopenharmony_ci assert(dst->Index == 0); 183bf215546Sopenharmony_ci } 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci return 1; 186bf215546Sopenharmony_ci} 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_cistatic void ei_vector1(struct r300_vertex_program_code *vp, 189bf215546Sopenharmony_ci unsigned int hw_opcode, 190bf215546Sopenharmony_ci struct rc_sub_instruction *vpi, 191bf215546Sopenharmony_ci unsigned int * inst) 192bf215546Sopenharmony_ci{ 193bf215546Sopenharmony_ci inst[0] = PVS_OP_DST_OPERAND(hw_opcode, 194bf215546Sopenharmony_ci 0, 195bf215546Sopenharmony_ci 0, 196bf215546Sopenharmony_ci t_dst_index(vp, &vpi->DstReg), 197bf215546Sopenharmony_ci t_dst_mask(vpi->DstReg.WriteMask), 198bf215546Sopenharmony_ci t_dst_class(vpi->DstReg.File), 199bf215546Sopenharmony_ci vpi->SaturateMode == RC_SATURATE_ZERO_ONE); 200bf215546Sopenharmony_ci inst[1] = t_src(vp, &vpi->SrcReg[0]); 201bf215546Sopenharmony_ci inst[2] = __CONST(0, RC_SWIZZLE_ZERO); 202bf215546Sopenharmony_ci inst[3] = __CONST(0, RC_SWIZZLE_ZERO); 203bf215546Sopenharmony_ci} 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_cistatic void ei_vector2(struct r300_vertex_program_code *vp, 206bf215546Sopenharmony_ci unsigned int hw_opcode, 207bf215546Sopenharmony_ci struct rc_sub_instruction *vpi, 208bf215546Sopenharmony_ci unsigned int * inst) 209bf215546Sopenharmony_ci{ 210bf215546Sopenharmony_ci inst[0] = PVS_OP_DST_OPERAND(hw_opcode, 211bf215546Sopenharmony_ci 0, 212bf215546Sopenharmony_ci 0, 213bf215546Sopenharmony_ci t_dst_index(vp, &vpi->DstReg), 214bf215546Sopenharmony_ci t_dst_mask(vpi->DstReg.WriteMask), 215bf215546Sopenharmony_ci t_dst_class(vpi->DstReg.File), 216bf215546Sopenharmony_ci vpi->SaturateMode == RC_SATURATE_ZERO_ONE); 217bf215546Sopenharmony_ci inst[1] = t_src(vp, &vpi->SrcReg[0]); 218bf215546Sopenharmony_ci inst[2] = t_src(vp, &vpi->SrcReg[1]); 219bf215546Sopenharmony_ci inst[3] = __CONST(1, RC_SWIZZLE_ZERO); 220bf215546Sopenharmony_ci} 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_cistatic void ei_math1(struct r300_vertex_program_code *vp, 223bf215546Sopenharmony_ci unsigned int hw_opcode, 224bf215546Sopenharmony_ci struct rc_sub_instruction *vpi, 225bf215546Sopenharmony_ci unsigned int * inst) 226bf215546Sopenharmony_ci{ 227bf215546Sopenharmony_ci inst[0] = PVS_OP_DST_OPERAND(hw_opcode, 228bf215546Sopenharmony_ci 1, 229bf215546Sopenharmony_ci 0, 230bf215546Sopenharmony_ci t_dst_index(vp, &vpi->DstReg), 231bf215546Sopenharmony_ci t_dst_mask(vpi->DstReg.WriteMask), 232bf215546Sopenharmony_ci t_dst_class(vpi->DstReg.File), 233bf215546Sopenharmony_ci vpi->SaturateMode == RC_SATURATE_ZERO_ONE); 234bf215546Sopenharmony_ci inst[1] = t_src_scalar(vp, &vpi->SrcReg[0]); 235bf215546Sopenharmony_ci inst[2] = __CONST(0, RC_SWIZZLE_ZERO); 236bf215546Sopenharmony_ci inst[3] = __CONST(0, RC_SWIZZLE_ZERO); 237bf215546Sopenharmony_ci} 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_cistatic void ei_lit(struct r300_vertex_program_code *vp, 240bf215546Sopenharmony_ci struct rc_sub_instruction *vpi, 241bf215546Sopenharmony_ci unsigned int * inst) 242bf215546Sopenharmony_ci{ 243bf215546Sopenharmony_ci //LIT TMP 1.Y Z TMP 1{} {X W Z Y} TMP 1{} {Y W Z X} TMP 1{} {Y X Z W} 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci inst[0] = PVS_OP_DST_OPERAND(ME_LIGHT_COEFF_DX, 246bf215546Sopenharmony_ci 1, 247bf215546Sopenharmony_ci 0, 248bf215546Sopenharmony_ci t_dst_index(vp, &vpi->DstReg), 249bf215546Sopenharmony_ci t_dst_mask(vpi->DstReg.WriteMask), 250bf215546Sopenharmony_ci t_dst_class(vpi->DstReg.File), 251bf215546Sopenharmony_ci vpi->SaturateMode == RC_SATURATE_ZERO_ONE); 252bf215546Sopenharmony_ci /* NOTE: Users swizzling might not work. */ 253bf215546Sopenharmony_ci inst[1] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X 254bf215546Sopenharmony_ci t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W 255bf215546Sopenharmony_ci PVS_SRC_SELECT_FORCE_0, // Z 256bf215546Sopenharmony_ci t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y 257bf215546Sopenharmony_ci t_src_class(vpi->SrcReg[0].File), 258bf215546Sopenharmony_ci vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) | 259bf215546Sopenharmony_ci (vpi->SrcReg[0].RelAddr << 4); 260bf215546Sopenharmony_ci inst[2] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y 261bf215546Sopenharmony_ci t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W 262bf215546Sopenharmony_ci PVS_SRC_SELECT_FORCE_0, // Z 263bf215546Sopenharmony_ci t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X 264bf215546Sopenharmony_ci t_src_class(vpi->SrcReg[0].File), 265bf215546Sopenharmony_ci vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) | 266bf215546Sopenharmony_ci (vpi->SrcReg[0].RelAddr << 4); 267bf215546Sopenharmony_ci inst[3] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y 268bf215546Sopenharmony_ci t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X 269bf215546Sopenharmony_ci PVS_SRC_SELECT_FORCE_0, // Z 270bf215546Sopenharmony_ci t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W 271bf215546Sopenharmony_ci t_src_class(vpi->SrcReg[0].File), 272bf215546Sopenharmony_ci vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) | 273bf215546Sopenharmony_ci (vpi->SrcReg[0].RelAddr << 4); 274bf215546Sopenharmony_ci} 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_cistatic void ei_mad(struct r300_vertex_program_code *vp, 277bf215546Sopenharmony_ci struct rc_sub_instruction *vpi, 278bf215546Sopenharmony_ci unsigned int * inst) 279bf215546Sopenharmony_ci{ 280bf215546Sopenharmony_ci unsigned int i; 281bf215546Sopenharmony_ci /* Remarks about hardware limitations of MAD 282bf215546Sopenharmony_ci * (please preserve this comment, as this information is _NOT_ 283bf215546Sopenharmony_ci * in the documentation provided by AMD). 284bf215546Sopenharmony_ci * 285bf215546Sopenharmony_ci * As described in the documentation, MAD with three unique temporary 286bf215546Sopenharmony_ci * source registers requires the use of the macro version. 287bf215546Sopenharmony_ci * 288bf215546Sopenharmony_ci * However (and this is not mentioned in the documentation), apparently 289bf215546Sopenharmony_ci * the macro version is _NOT_ a full superset of the normal version. 290bf215546Sopenharmony_ci * In particular, the macro version does not always work when relative 291bf215546Sopenharmony_ci * addressing is used in the source operands. 292bf215546Sopenharmony_ci * 293bf215546Sopenharmony_ci * This limitation caused incorrect rendering in Sauerbraten's OpenGL 294bf215546Sopenharmony_ci * assembly shader path when using medium quality animations 295bf215546Sopenharmony_ci * (i.e. animations with matrix blending instead of quaternion blending). 296bf215546Sopenharmony_ci * 297bf215546Sopenharmony_ci * Unfortunately, I (nha) have been unable to extract a Piglit regression 298bf215546Sopenharmony_ci * test for this issue - for some reason, it is possible to have vertex 299bf215546Sopenharmony_ci * programs whose prefix is *exactly* the same as the prefix of the 300bf215546Sopenharmony_ci * offending program in Sauerbraten up to the offending instruction 301bf215546Sopenharmony_ci * without causing any trouble. 302bf215546Sopenharmony_ci * 303bf215546Sopenharmony_ci * Bottom line: Only use the macro version only when really necessary; 304bf215546Sopenharmony_ci * according to AMD docs, this should improve performance by one clock 305bf215546Sopenharmony_ci * as a nice side bonus. 306bf215546Sopenharmony_ci */ 307bf215546Sopenharmony_ci if (vpi->SrcReg[0].File == RC_FILE_TEMPORARY && 308bf215546Sopenharmony_ci vpi->SrcReg[1].File == RC_FILE_TEMPORARY && 309bf215546Sopenharmony_ci vpi->SrcReg[2].File == RC_FILE_TEMPORARY && 310bf215546Sopenharmony_ci vpi->SrcReg[0].Index != vpi->SrcReg[1].Index && 311bf215546Sopenharmony_ci vpi->SrcReg[0].Index != vpi->SrcReg[2].Index && 312bf215546Sopenharmony_ci vpi->SrcReg[1].Index != vpi->SrcReg[2].Index) { 313bf215546Sopenharmony_ci inst[0] = PVS_OP_DST_OPERAND(PVS_MACRO_OP_2CLK_MADD, 314bf215546Sopenharmony_ci 0, 315bf215546Sopenharmony_ci 1, 316bf215546Sopenharmony_ci t_dst_index(vp, &vpi->DstReg), 317bf215546Sopenharmony_ci t_dst_mask(vpi->DstReg.WriteMask), 318bf215546Sopenharmony_ci t_dst_class(vpi->DstReg.File), 319bf215546Sopenharmony_ci vpi->SaturateMode == RC_SATURATE_ZERO_ONE); 320bf215546Sopenharmony_ci } else { 321bf215546Sopenharmony_ci inst[0] = PVS_OP_DST_OPERAND(VE_MULTIPLY_ADD, 322bf215546Sopenharmony_ci 0, 323bf215546Sopenharmony_ci 0, 324bf215546Sopenharmony_ci t_dst_index(vp, &vpi->DstReg), 325bf215546Sopenharmony_ci t_dst_mask(vpi->DstReg.WriteMask), 326bf215546Sopenharmony_ci t_dst_class(vpi->DstReg.File), 327bf215546Sopenharmony_ci vpi->SaturateMode == RC_SATURATE_ZERO_ONE); 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci /* Arguments with constant swizzles still count as a unique 330bf215546Sopenharmony_ci * temporary, so we should make sure these arguments share a 331bf215546Sopenharmony_ci * register index with one of the other arguments. */ 332bf215546Sopenharmony_ci for (i = 0; i < 3; i++) { 333bf215546Sopenharmony_ci unsigned int j; 334bf215546Sopenharmony_ci if (vpi->SrcReg[i].File != RC_FILE_NONE) 335bf215546Sopenharmony_ci continue; 336bf215546Sopenharmony_ci 337bf215546Sopenharmony_ci for (j = 0; j < 3; j++) { 338bf215546Sopenharmony_ci if (i != j) { 339bf215546Sopenharmony_ci vpi->SrcReg[i].Index = 340bf215546Sopenharmony_ci vpi->SrcReg[j].Index; 341bf215546Sopenharmony_ci break; 342bf215546Sopenharmony_ci } 343bf215546Sopenharmony_ci } 344bf215546Sopenharmony_ci } 345bf215546Sopenharmony_ci } 346bf215546Sopenharmony_ci inst[1] = t_src(vp, &vpi->SrcReg[0]); 347bf215546Sopenharmony_ci inst[2] = t_src(vp, &vpi->SrcReg[1]); 348bf215546Sopenharmony_ci inst[3] = t_src(vp, &vpi->SrcReg[2]); 349bf215546Sopenharmony_ci} 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_cistatic void ei_pow(struct r300_vertex_program_code *vp, 352bf215546Sopenharmony_ci struct rc_sub_instruction *vpi, 353bf215546Sopenharmony_ci unsigned int * inst) 354bf215546Sopenharmony_ci{ 355bf215546Sopenharmony_ci inst[0] = PVS_OP_DST_OPERAND(ME_POWER_FUNC_FF, 356bf215546Sopenharmony_ci 1, 357bf215546Sopenharmony_ci 0, 358bf215546Sopenharmony_ci t_dst_index(vp, &vpi->DstReg), 359bf215546Sopenharmony_ci t_dst_mask(vpi->DstReg.WriteMask), 360bf215546Sopenharmony_ci t_dst_class(vpi->DstReg.File), 361bf215546Sopenharmony_ci vpi->SaturateMode == RC_SATURATE_ZERO_ONE); 362bf215546Sopenharmony_ci inst[1] = t_src_scalar(vp, &vpi->SrcReg[0]); 363bf215546Sopenharmony_ci inst[2] = __CONST(0, RC_SWIZZLE_ZERO); 364bf215546Sopenharmony_ci inst[3] = t_src_scalar(vp, &vpi->SrcReg[1]); 365bf215546Sopenharmony_ci} 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_cistatic void translate_vertex_program(struct radeon_compiler *c, void *user) 368bf215546Sopenharmony_ci{ 369bf215546Sopenharmony_ci struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c; 370bf215546Sopenharmony_ci struct rc_instruction *rci; 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci unsigned loops[R500_PVS_MAX_LOOP_DEPTH] = {}; 373bf215546Sopenharmony_ci unsigned loop_depth = 0; 374bf215546Sopenharmony_ci bool last_input_read_at_loop_end = false; 375bf215546Sopenharmony_ci bool last_pos_write_at_loop_end = false; 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci compiler->code->pos_end = 0; /* Not supported yet */ 378bf215546Sopenharmony_ci compiler->code->length = 0; 379bf215546Sopenharmony_ci compiler->code->num_temporaries = 0; 380bf215546Sopenharmony_ci compiler->code->last_input_read = 0; 381bf215546Sopenharmony_ci compiler->code->last_pos_write = 0; 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci compiler->SetHwInputOutput(compiler); 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci for(rci = compiler->Base.Program.Instructions.Next; rci != &compiler->Base.Program.Instructions; rci = rci->Next) { 386bf215546Sopenharmony_ci struct rc_sub_instruction *vpi = &rci->U.I; 387bf215546Sopenharmony_ci unsigned int *inst = compiler->code->body.d + compiler->code->length; 388bf215546Sopenharmony_ci const struct rc_opcode_info *info = rc_get_opcode_info(vpi->Opcode); 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_ci /* Skip instructions writing to non-existing destination */ 391bf215546Sopenharmony_ci if (!valid_dst(compiler->code, &vpi->DstReg)) 392bf215546Sopenharmony_ci continue; 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci if (info->HasDstReg) { 395bf215546Sopenharmony_ci /* Neither is Saturate. */ 396bf215546Sopenharmony_ci if (vpi->SaturateMode != RC_SATURATE_NONE && !c->is_r500) { 397bf215546Sopenharmony_ci rc_error(&compiler->Base, "Vertex program does not support the Saturate " 398bf215546Sopenharmony_ci "modifier (yet).\n"); 399bf215546Sopenharmony_ci } 400bf215546Sopenharmony_ci } 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_ci if (compiler->code->length >= c->max_alu_insts * 4) { 403bf215546Sopenharmony_ci rc_error(&compiler->Base, "Vertex program has too many instructions\n"); 404bf215546Sopenharmony_ci return; 405bf215546Sopenharmony_ci } 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci assert(compiler->Base.is_r500 || 408bf215546Sopenharmony_ci (vpi->Opcode != RC_OPCODE_SEQ && 409bf215546Sopenharmony_ci vpi->Opcode != RC_OPCODE_SNE)); 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci switch (vpi->Opcode) { 412bf215546Sopenharmony_ci case RC_OPCODE_ADD: ei_vector2(compiler->code, VE_ADD, vpi, inst); break; 413bf215546Sopenharmony_ci case RC_OPCODE_ARL: ei_vector1(compiler->code, VE_FLT2FIX_DX, vpi, inst); break; 414bf215546Sopenharmony_ci case RC_OPCODE_ARR: ei_vector1(compiler->code, VE_FLT2FIX_DX_RND, vpi, inst); break; 415bf215546Sopenharmony_ci case RC_OPCODE_COS: ei_math1(compiler->code, ME_COS, vpi, inst); break; 416bf215546Sopenharmony_ci case RC_OPCODE_DP4: ei_vector2(compiler->code, VE_DOT_PRODUCT, vpi, inst); break; 417bf215546Sopenharmony_ci case RC_OPCODE_DST: ei_vector2(compiler->code, VE_DISTANCE_VECTOR, vpi, inst); break; 418bf215546Sopenharmony_ci case RC_OPCODE_EX2: ei_math1(compiler->code, ME_EXP_BASE2_FULL_DX, vpi, inst); break; 419bf215546Sopenharmony_ci case RC_OPCODE_EXP: ei_math1(compiler->code, ME_EXP_BASE2_DX, vpi, inst); break; 420bf215546Sopenharmony_ci case RC_OPCODE_FRC: ei_vector1(compiler->code, VE_FRACTION, vpi, inst); break; 421bf215546Sopenharmony_ci case RC_OPCODE_LG2: ei_math1(compiler->code, ME_LOG_BASE2_FULL_DX, vpi, inst); break; 422bf215546Sopenharmony_ci case RC_OPCODE_LIT: ei_lit(compiler->code, vpi, inst); break; 423bf215546Sopenharmony_ci case RC_OPCODE_LOG: ei_math1(compiler->code, ME_LOG_BASE2_DX, vpi, inst); break; 424bf215546Sopenharmony_ci case RC_OPCODE_MAD: ei_mad(compiler->code, vpi, inst); break; 425bf215546Sopenharmony_ci case RC_OPCODE_MAX: ei_vector2(compiler->code, VE_MAXIMUM, vpi, inst); break; 426bf215546Sopenharmony_ci case RC_OPCODE_MIN: ei_vector2(compiler->code, VE_MINIMUM, vpi, inst); break; 427bf215546Sopenharmony_ci case RC_OPCODE_MOV: ei_vector1(compiler->code, VE_ADD, vpi, inst); break; 428bf215546Sopenharmony_ci case RC_OPCODE_MUL: ei_vector2(compiler->code, VE_MULTIPLY, vpi, inst); break; 429bf215546Sopenharmony_ci case RC_OPCODE_POW: ei_pow(compiler->code, vpi, inst); break; 430bf215546Sopenharmony_ci case RC_OPCODE_RCP: ei_math1(compiler->code, ME_RECIP_DX, vpi, inst); break; 431bf215546Sopenharmony_ci case RC_OPCODE_RSQ: ei_math1(compiler->code, ME_RECIP_SQRT_DX, vpi, inst); break; 432bf215546Sopenharmony_ci case RC_OPCODE_SEQ: ei_vector2(compiler->code, VE_SET_EQUAL, vpi, inst); break; 433bf215546Sopenharmony_ci case RC_OPCODE_SGE: ei_vector2(compiler->code, VE_SET_GREATER_THAN_EQUAL, vpi, inst); break; 434bf215546Sopenharmony_ci case RC_OPCODE_SIN: ei_math1(compiler->code, ME_SIN, vpi, inst); break; 435bf215546Sopenharmony_ci case RC_OPCODE_SLT: ei_vector2(compiler->code, VE_SET_LESS_THAN, vpi, inst); break; 436bf215546Sopenharmony_ci case RC_OPCODE_SNE: ei_vector2(compiler->code, VE_SET_NOT_EQUAL, vpi, inst); break; 437bf215546Sopenharmony_ci case RC_OPCODE_BGNLOOP: 438bf215546Sopenharmony_ci { 439bf215546Sopenharmony_ci if ((!compiler->Base.is_r500 440bf215546Sopenharmony_ci && loop_depth >= R300_VS_MAX_LOOP_DEPTH) 441bf215546Sopenharmony_ci || loop_depth >= R500_PVS_MAX_LOOP_DEPTH) { 442bf215546Sopenharmony_ci rc_error(&compiler->Base, 443bf215546Sopenharmony_ci "Loops are nested too deep."); 444bf215546Sopenharmony_ci return; 445bf215546Sopenharmony_ci } 446bf215546Sopenharmony_ci loops[loop_depth++] = ((compiler->code->length)/ 4) + 1; 447bf215546Sopenharmony_ci break; 448bf215546Sopenharmony_ci } 449bf215546Sopenharmony_ci case RC_OPCODE_ENDLOOP: 450bf215546Sopenharmony_ci { 451bf215546Sopenharmony_ci unsigned int act_addr; 452bf215546Sopenharmony_ci unsigned int last_addr; 453bf215546Sopenharmony_ci unsigned int ret_addr; 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci if (loop_depth == 1 && last_input_read_at_loop_end) { 456bf215546Sopenharmony_ci compiler->code->last_input_read = compiler->code->length / 4; 457bf215546Sopenharmony_ci last_input_read_at_loop_end = false; 458bf215546Sopenharmony_ci } 459bf215546Sopenharmony_ci if (loop_depth == 1 && last_pos_write_at_loop_end) { 460bf215546Sopenharmony_ci compiler->code->last_pos_write = compiler->code->length / 4; 461bf215546Sopenharmony_ci last_pos_write_at_loop_end = false; 462bf215546Sopenharmony_ci } 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci ret_addr = loops[--loop_depth]; 465bf215546Sopenharmony_ci act_addr = ret_addr - 1; 466bf215546Sopenharmony_ci last_addr = (compiler->code->length / 4) - 1; 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci if (loop_depth >= R300_VS_MAX_FC_OPS) { 469bf215546Sopenharmony_ci rc_error(&compiler->Base, 470bf215546Sopenharmony_ci "Too many flow control instructions."); 471bf215546Sopenharmony_ci return; 472bf215546Sopenharmony_ci } 473bf215546Sopenharmony_ci if (compiler->Base.is_r500) { 474bf215546Sopenharmony_ci compiler->code->fc_op_addrs.r500 475bf215546Sopenharmony_ci [compiler->code->num_fc_ops].lw = 476bf215546Sopenharmony_ci R500_PVS_FC_ACT_ADRS(act_addr) 477bf215546Sopenharmony_ci | R500_PVS_FC_LOOP_CNT_JMP_INST(0x00ff) 478bf215546Sopenharmony_ci ; 479bf215546Sopenharmony_ci compiler->code->fc_op_addrs.r500 480bf215546Sopenharmony_ci [compiler->code->num_fc_ops].uw = 481bf215546Sopenharmony_ci R500_PVS_FC_LAST_INST(last_addr) 482bf215546Sopenharmony_ci | R500_PVS_FC_RTN_INST(ret_addr) 483bf215546Sopenharmony_ci ; 484bf215546Sopenharmony_ci } else { 485bf215546Sopenharmony_ci compiler->code->fc_op_addrs.r300 486bf215546Sopenharmony_ci [compiler->code->num_fc_ops] = 487bf215546Sopenharmony_ci R300_PVS_FC_ACT_ADRS(act_addr) 488bf215546Sopenharmony_ci | R300_PVS_FC_LOOP_CNT_JMP_INST(0xff) 489bf215546Sopenharmony_ci | R300_PVS_FC_LAST_INST(last_addr) 490bf215546Sopenharmony_ci | R300_PVS_FC_RTN_INST(ret_addr) 491bf215546Sopenharmony_ci ; 492bf215546Sopenharmony_ci } 493bf215546Sopenharmony_ci compiler->code->fc_loop_index[compiler->code->num_fc_ops] = 494bf215546Sopenharmony_ci R300_PVS_FC_LOOP_INIT_VAL(0x0) 495bf215546Sopenharmony_ci | R300_PVS_FC_LOOP_STEP_VAL(0x1) 496bf215546Sopenharmony_ci ; 497bf215546Sopenharmony_ci compiler->code->fc_ops |= R300_VAP_PVS_FC_OPC_LOOP( 498bf215546Sopenharmony_ci compiler->code->num_fc_ops); 499bf215546Sopenharmony_ci compiler->code->num_fc_ops++; 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci break; 502bf215546Sopenharmony_ci } 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci case RC_ME_PRED_SET_CLR: 505bf215546Sopenharmony_ci ei_math1(compiler->code, ME_PRED_SET_CLR, vpi, inst); 506bf215546Sopenharmony_ci break; 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ci case RC_ME_PRED_SET_INV: 509bf215546Sopenharmony_ci ei_math1(compiler->code, ME_PRED_SET_INV, vpi, inst); 510bf215546Sopenharmony_ci break; 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci case RC_ME_PRED_SET_POP: 513bf215546Sopenharmony_ci ei_math1(compiler->code, ME_PRED_SET_POP, vpi, inst); 514bf215546Sopenharmony_ci break; 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_ci case RC_ME_PRED_SET_RESTORE: 517bf215546Sopenharmony_ci ei_math1(compiler->code, ME_PRED_SET_RESTORE, vpi, inst); 518bf215546Sopenharmony_ci break; 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ci case RC_ME_PRED_SEQ: 521bf215546Sopenharmony_ci ei_math1(compiler->code, ME_PRED_SET_EQ, vpi, inst); 522bf215546Sopenharmony_ci break; 523bf215546Sopenharmony_ci 524bf215546Sopenharmony_ci case RC_ME_PRED_SNEQ: 525bf215546Sopenharmony_ci ei_math1(compiler->code, ME_PRED_SET_NEQ, vpi, inst); 526bf215546Sopenharmony_ci break; 527bf215546Sopenharmony_ci 528bf215546Sopenharmony_ci case RC_VE_PRED_SNEQ_PUSH: 529bf215546Sopenharmony_ci ei_vector2(compiler->code, VE_PRED_SET_NEQ_PUSH, 530bf215546Sopenharmony_ci vpi, inst); 531bf215546Sopenharmony_ci break; 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci default: 534bf215546Sopenharmony_ci rc_error(&compiler->Base, "Unknown opcode %s\n", info->Name); 535bf215546Sopenharmony_ci return; 536bf215546Sopenharmony_ci } 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci if (vpi->DstReg.Pred != RC_PRED_DISABLED) { 539bf215546Sopenharmony_ci inst[0] |= (PVS_DST_PRED_ENABLE_MASK 540bf215546Sopenharmony_ci << PVS_DST_PRED_ENABLE_SHIFT); 541bf215546Sopenharmony_ci if (vpi->DstReg.Pred == RC_PRED_SET) { 542bf215546Sopenharmony_ci inst[0] |= (PVS_DST_PRED_SENSE_MASK 543bf215546Sopenharmony_ci << PVS_DST_PRED_SENSE_SHIFT); 544bf215546Sopenharmony_ci } 545bf215546Sopenharmony_ci } 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci /* Update the number of temporaries. */ 548bf215546Sopenharmony_ci if (info->HasDstReg && vpi->DstReg.File == RC_FILE_TEMPORARY && 549bf215546Sopenharmony_ci vpi->DstReg.Index >= compiler->code->num_temporaries) 550bf215546Sopenharmony_ci compiler->code->num_temporaries = vpi->DstReg.Index + 1; 551bf215546Sopenharmony_ci 552bf215546Sopenharmony_ci /* last instruction that writes position */ 553bf215546Sopenharmony_ci if (info->HasDstReg && vpi->DstReg.File == RC_FILE_OUTPUT && 554bf215546Sopenharmony_ci t_dst_index(compiler->code, &vpi->DstReg) == 0) { 555bf215546Sopenharmony_ci if (loop_depth == 0) 556bf215546Sopenharmony_ci compiler->code->last_pos_write = compiler->code->length / 4; 557bf215546Sopenharmony_ci else 558bf215546Sopenharmony_ci last_pos_write_at_loop_end = true; 559bf215546Sopenharmony_ci } 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci for (unsigned i = 0; i < info->NumSrcRegs; i++) { 562bf215546Sopenharmony_ci if (vpi->SrcReg[i].File == RC_FILE_TEMPORARY && 563bf215546Sopenharmony_ci vpi->SrcReg[i].Index >= compiler->code->num_temporaries) 564bf215546Sopenharmony_ci compiler->code->num_temporaries = vpi->SrcReg[i].Index + 1; 565bf215546Sopenharmony_ci if (vpi->SrcReg[i].File == RC_FILE_INPUT) { 566bf215546Sopenharmony_ci if (loop_depth == 0) 567bf215546Sopenharmony_ci compiler->code->last_input_read = compiler->code->length / 4; 568bf215546Sopenharmony_ci else 569bf215546Sopenharmony_ci last_input_read_at_loop_end = true; 570bf215546Sopenharmony_ci } 571bf215546Sopenharmony_ci 572bf215546Sopenharmony_ci } 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_ci 575bf215546Sopenharmony_ci if (compiler->code->num_temporaries > compiler->Base.max_temp_regs) { 576bf215546Sopenharmony_ci rc_error(&compiler->Base, "Too many temporaries.\n"); 577bf215546Sopenharmony_ci return; 578bf215546Sopenharmony_ci } 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ci compiler->code->length += 4; 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci if (compiler->Base.Error) 583bf215546Sopenharmony_ci return; 584bf215546Sopenharmony_ci } 585bf215546Sopenharmony_ci} 586bf215546Sopenharmony_ci 587bf215546Sopenharmony_cistruct temporary_allocation { 588bf215546Sopenharmony_ci unsigned int Allocated:1; 589bf215546Sopenharmony_ci unsigned int HwTemp:15; 590bf215546Sopenharmony_ci struct rc_instruction * LastRead; 591bf215546Sopenharmony_ci}; 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_cistatic int get_reg(struct radeon_compiler *c, struct temporary_allocation *ta, bool *hwtemps, 594bf215546Sopenharmony_ci unsigned int orig) 595bf215546Sopenharmony_ci{ 596bf215546Sopenharmony_ci if (!ta[orig].Allocated) { 597bf215546Sopenharmony_ci int j; 598bf215546Sopenharmony_ci for (j = 0; j < c->max_temp_regs; ++j) 599bf215546Sopenharmony_ci { 600bf215546Sopenharmony_ci if (!hwtemps[j]) 601bf215546Sopenharmony_ci break; 602bf215546Sopenharmony_ci } 603bf215546Sopenharmony_ci ta[orig].Allocated = 1; 604bf215546Sopenharmony_ci ta[orig].HwTemp = j; 605bf215546Sopenharmony_ci hwtemps[ta[orig].HwTemp] = true; 606bf215546Sopenharmony_ci } 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci return ta[orig].HwTemp; 609bf215546Sopenharmony_ci} 610bf215546Sopenharmony_ci 611bf215546Sopenharmony_cistatic void allocate_temporary_registers(struct radeon_compiler *c, void *user) 612bf215546Sopenharmony_ci{ 613bf215546Sopenharmony_ci struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c; 614bf215546Sopenharmony_ci struct rc_instruction *inst; 615bf215546Sopenharmony_ci struct rc_instruction *end_loop = NULL; 616bf215546Sopenharmony_ci unsigned int num_orig_temps = 0; 617bf215546Sopenharmony_ci bool hwtemps[RC_REGISTER_MAX_INDEX]; 618bf215546Sopenharmony_ci struct temporary_allocation * ta; 619bf215546Sopenharmony_ci unsigned int i; 620bf215546Sopenharmony_ci 621bf215546Sopenharmony_ci memset(hwtemps, 0, sizeof(hwtemps)); 622bf215546Sopenharmony_ci 623bf215546Sopenharmony_ci rc_recompute_ips(c); 624bf215546Sopenharmony_ci 625bf215546Sopenharmony_ci /* Pass 1: Count original temporaries. */ 626bf215546Sopenharmony_ci for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { 627bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); 628bf215546Sopenharmony_ci 629bf215546Sopenharmony_ci for (i = 0; i < opcode->NumSrcRegs; ++i) { 630bf215546Sopenharmony_ci if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) { 631bf215546Sopenharmony_ci if (inst->U.I.SrcReg[i].Index >= num_orig_temps) 632bf215546Sopenharmony_ci num_orig_temps = inst->U.I.SrcReg[i].Index + 1; 633bf215546Sopenharmony_ci } 634bf215546Sopenharmony_ci } 635bf215546Sopenharmony_ci 636bf215546Sopenharmony_ci if (opcode->HasDstReg) { 637bf215546Sopenharmony_ci if (inst->U.I.DstReg.File == RC_FILE_TEMPORARY) { 638bf215546Sopenharmony_ci if (inst->U.I.DstReg.Index >= num_orig_temps) 639bf215546Sopenharmony_ci num_orig_temps = inst->U.I.DstReg.Index + 1; 640bf215546Sopenharmony_ci } 641bf215546Sopenharmony_ci } 642bf215546Sopenharmony_ci } 643bf215546Sopenharmony_ci 644bf215546Sopenharmony_ci ta = (struct temporary_allocation*)memory_pool_malloc(&compiler->Base.Pool, 645bf215546Sopenharmony_ci sizeof(struct temporary_allocation) * num_orig_temps); 646bf215546Sopenharmony_ci memset(ta, 0, sizeof(struct temporary_allocation) * num_orig_temps); 647bf215546Sopenharmony_ci 648bf215546Sopenharmony_ci /* Pass 2: Determine original temporary lifetimes */ 649bf215546Sopenharmony_ci for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { 650bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); 651bf215546Sopenharmony_ci /* Instructions inside of loops need to use the ENDLOOP 652bf215546Sopenharmony_ci * instruction as their LastRead. */ 653bf215546Sopenharmony_ci if (!end_loop && inst->U.I.Opcode == RC_OPCODE_BGNLOOP) 654bf215546Sopenharmony_ci end_loop = rc_match_bgnloop(inst); 655bf215546Sopenharmony_ci 656bf215546Sopenharmony_ci if (inst == end_loop) { 657bf215546Sopenharmony_ci end_loop = NULL; 658bf215546Sopenharmony_ci continue; 659bf215546Sopenharmony_ci } 660bf215546Sopenharmony_ci 661bf215546Sopenharmony_ci for (i = 0; i < opcode->NumSrcRegs; ++i) { 662bf215546Sopenharmony_ci if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) { 663bf215546Sopenharmony_ci ta[inst->U.I.SrcReg[i].Index].LastRead = end_loop ? end_loop : inst; 664bf215546Sopenharmony_ci } 665bf215546Sopenharmony_ci } 666bf215546Sopenharmony_ci } 667bf215546Sopenharmony_ci 668bf215546Sopenharmony_ci /* Pass 3: Register allocation */ 669bf215546Sopenharmony_ci for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { 670bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); 671bf215546Sopenharmony_ci 672bf215546Sopenharmony_ci for (i = 0; i < opcode->NumSrcRegs; ++i) { 673bf215546Sopenharmony_ci if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) { 674bf215546Sopenharmony_ci unsigned int orig = inst->U.I.SrcReg[i].Index; 675bf215546Sopenharmony_ci inst->U.I.SrcReg[i].Index = get_reg(c, ta, hwtemps, orig); 676bf215546Sopenharmony_ci 677bf215546Sopenharmony_ci if (ta[orig].Allocated && inst == ta[orig].LastRead) 678bf215546Sopenharmony_ci hwtemps[ta[orig].HwTemp] = false; 679bf215546Sopenharmony_ci } 680bf215546Sopenharmony_ci } 681bf215546Sopenharmony_ci 682bf215546Sopenharmony_ci if (opcode->HasDstReg) { 683bf215546Sopenharmony_ci if (inst->U.I.DstReg.File == RC_FILE_TEMPORARY) { 684bf215546Sopenharmony_ci unsigned int orig = inst->U.I.DstReg.Index; 685bf215546Sopenharmony_ci inst->U.I.DstReg.Index = get_reg(c, ta, hwtemps, orig); 686bf215546Sopenharmony_ci } 687bf215546Sopenharmony_ci } 688bf215546Sopenharmony_ci } 689bf215546Sopenharmony_ci} 690bf215546Sopenharmony_ci 691bf215546Sopenharmony_ci/** 692bf215546Sopenharmony_ci * R3xx-R4xx vertex engine does not support the Absolute source operand modifier 693bf215546Sopenharmony_ci * and the Saturate opcode modifier. Only Absolute is currently transformed. 694bf215546Sopenharmony_ci */ 695bf215546Sopenharmony_cistatic int transform_nonnative_modifiers( 696bf215546Sopenharmony_ci struct radeon_compiler *c, 697bf215546Sopenharmony_ci struct rc_instruction *inst, 698bf215546Sopenharmony_ci void* unused) 699bf215546Sopenharmony_ci{ 700bf215546Sopenharmony_ci const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->U.I.Opcode); 701bf215546Sopenharmony_ci unsigned i; 702bf215546Sopenharmony_ci 703bf215546Sopenharmony_ci /* Transform ABS(a) to MAX(a, -a). */ 704bf215546Sopenharmony_ci for (i = 0; i < opcode->NumSrcRegs; i++) { 705bf215546Sopenharmony_ci if (inst->U.I.SrcReg[i].Abs) { 706bf215546Sopenharmony_ci struct rc_instruction *new_inst; 707bf215546Sopenharmony_ci unsigned temp; 708bf215546Sopenharmony_ci 709bf215546Sopenharmony_ci inst->U.I.SrcReg[i].Abs = 0; 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_ci temp = rc_find_free_temporary(c); 712bf215546Sopenharmony_ci 713bf215546Sopenharmony_ci new_inst = rc_insert_new_instruction(c, inst->Prev); 714bf215546Sopenharmony_ci new_inst->U.I.Opcode = RC_OPCODE_MAX; 715bf215546Sopenharmony_ci new_inst->U.I.DstReg.File = RC_FILE_TEMPORARY; 716bf215546Sopenharmony_ci new_inst->U.I.DstReg.Index = temp; 717bf215546Sopenharmony_ci new_inst->U.I.SrcReg[0] = inst->U.I.SrcReg[i]; 718bf215546Sopenharmony_ci new_inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; 719bf215546Sopenharmony_ci new_inst->U.I.SrcReg[1] = inst->U.I.SrcReg[i]; 720bf215546Sopenharmony_ci new_inst->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZW; 721bf215546Sopenharmony_ci new_inst->U.I.SrcReg[1].Negate ^= RC_MASK_XYZW; 722bf215546Sopenharmony_ci 723bf215546Sopenharmony_ci inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY; 724bf215546Sopenharmony_ci inst->U.I.SrcReg[i].Index = temp; 725bf215546Sopenharmony_ci inst->U.I.SrcReg[i].RelAddr = 0; 726bf215546Sopenharmony_ci } 727bf215546Sopenharmony_ci } 728bf215546Sopenharmony_ci return 1; 729bf215546Sopenharmony_ci} 730bf215546Sopenharmony_ci 731bf215546Sopenharmony_ci/** 732bf215546Sopenharmony_ci * Vertex engine cannot read two inputs or two constants at the same time. 733bf215546Sopenharmony_ci * Introduce intermediate MOVs to temporary registers to account for this. 734bf215546Sopenharmony_ci */ 735bf215546Sopenharmony_cistatic int transform_source_conflicts( 736bf215546Sopenharmony_ci struct radeon_compiler *c, 737bf215546Sopenharmony_ci struct rc_instruction* inst, 738bf215546Sopenharmony_ci void* unused) 739bf215546Sopenharmony_ci{ 740bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); 741bf215546Sopenharmony_ci 742bf215546Sopenharmony_ci if (opcode->NumSrcRegs == 3) { 743bf215546Sopenharmony_ci if (t_src_conflict(inst->U.I.SrcReg[1], inst->U.I.SrcReg[2]) 744bf215546Sopenharmony_ci || t_src_conflict(inst->U.I.SrcReg[0], inst->U.I.SrcReg[2])) { 745bf215546Sopenharmony_ci int tmpreg = rc_find_free_temporary(c); 746bf215546Sopenharmony_ci struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev); 747bf215546Sopenharmony_ci inst_mov->U.I.Opcode = RC_OPCODE_MOV; 748bf215546Sopenharmony_ci inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; 749bf215546Sopenharmony_ci inst_mov->U.I.DstReg.Index = tmpreg; 750bf215546Sopenharmony_ci inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[2]; 751bf215546Sopenharmony_ci inst_mov->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; 752bf215546Sopenharmony_ci inst_mov->U.I.SrcReg[0].Negate = 0; 753bf215546Sopenharmony_ci inst_mov->U.I.SrcReg[0].Abs = 0; 754bf215546Sopenharmony_ci 755bf215546Sopenharmony_ci inst->U.I.SrcReg[2].File = RC_FILE_TEMPORARY; 756bf215546Sopenharmony_ci inst->U.I.SrcReg[2].Index = tmpreg; 757bf215546Sopenharmony_ci inst->U.I.SrcReg[2].RelAddr = false; 758bf215546Sopenharmony_ci } 759bf215546Sopenharmony_ci } 760bf215546Sopenharmony_ci 761bf215546Sopenharmony_ci if (opcode->NumSrcRegs >= 2) { 762bf215546Sopenharmony_ci if (t_src_conflict(inst->U.I.SrcReg[1], inst->U.I.SrcReg[0])) { 763bf215546Sopenharmony_ci int tmpreg = rc_find_free_temporary(c); 764bf215546Sopenharmony_ci struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev); 765bf215546Sopenharmony_ci inst_mov->U.I.Opcode = RC_OPCODE_MOV; 766bf215546Sopenharmony_ci inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; 767bf215546Sopenharmony_ci inst_mov->U.I.DstReg.Index = tmpreg; 768bf215546Sopenharmony_ci inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[1]; 769bf215546Sopenharmony_ci inst_mov->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; 770bf215546Sopenharmony_ci inst_mov->U.I.SrcReg[0].Negate = 0; 771bf215546Sopenharmony_ci inst_mov->U.I.SrcReg[0].Abs = 0; 772bf215546Sopenharmony_ci 773bf215546Sopenharmony_ci inst->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; 774bf215546Sopenharmony_ci inst->U.I.SrcReg[1].Index = tmpreg; 775bf215546Sopenharmony_ci inst->U.I.SrcReg[1].RelAddr = false; 776bf215546Sopenharmony_ci } 777bf215546Sopenharmony_ci } 778bf215546Sopenharmony_ci 779bf215546Sopenharmony_ci return 1; 780bf215546Sopenharmony_ci} 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_cistatic void rc_vs_add_artificial_outputs(struct radeon_compiler *c, void *user) 783bf215546Sopenharmony_ci{ 784bf215546Sopenharmony_ci struct r300_vertex_program_compiler * compiler = (struct r300_vertex_program_compiler*)c; 785bf215546Sopenharmony_ci int i; 786bf215546Sopenharmony_ci 787bf215546Sopenharmony_ci for(i = 0; i < 32; ++i) { 788bf215546Sopenharmony_ci if ((compiler->RequiredOutputs & (1U << i)) && 789bf215546Sopenharmony_ci !(compiler->Base.Program.OutputsWritten & (1U << i))) { 790bf215546Sopenharmony_ci struct rc_instruction * inst = rc_insert_new_instruction(&compiler->Base, compiler->Base.Program.Instructions.Prev); 791bf215546Sopenharmony_ci inst->U.I.Opcode = RC_OPCODE_MOV; 792bf215546Sopenharmony_ci 793bf215546Sopenharmony_ci inst->U.I.DstReg.File = RC_FILE_OUTPUT; 794bf215546Sopenharmony_ci inst->U.I.DstReg.Index = i; 795bf215546Sopenharmony_ci inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; 796bf215546Sopenharmony_ci 797bf215546Sopenharmony_ci inst->U.I.SrcReg[0].File = RC_FILE_CONSTANT; 798bf215546Sopenharmony_ci inst->U.I.SrcReg[0].Index = 0; 799bf215546Sopenharmony_ci inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; 800bf215546Sopenharmony_ci 801bf215546Sopenharmony_ci compiler->Base.Program.OutputsWritten |= 1U << i; 802bf215546Sopenharmony_ci } 803bf215546Sopenharmony_ci } 804bf215546Sopenharmony_ci} 805bf215546Sopenharmony_ci 806bf215546Sopenharmony_cistatic int swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) 807bf215546Sopenharmony_ci{ 808bf215546Sopenharmony_ci (void) opcode; 809bf215546Sopenharmony_ci (void) reg; 810bf215546Sopenharmony_ci 811bf215546Sopenharmony_ci return 1; 812bf215546Sopenharmony_ci} 813bf215546Sopenharmony_ci 814bf215546Sopenharmony_cistatic void transform_negative_addressing(struct r300_vertex_program_compiler *c, 815bf215546Sopenharmony_ci struct rc_instruction *arl, 816bf215546Sopenharmony_ci struct rc_instruction *end, 817bf215546Sopenharmony_ci int min_offset) 818bf215546Sopenharmony_ci{ 819bf215546Sopenharmony_ci struct rc_instruction *inst, *add; 820bf215546Sopenharmony_ci unsigned const_swizzle; 821bf215546Sopenharmony_ci 822bf215546Sopenharmony_ci /* Transform ARL/ARR */ 823bf215546Sopenharmony_ci add = rc_insert_new_instruction(&c->Base, arl->Prev); 824bf215546Sopenharmony_ci add->U.I.Opcode = RC_OPCODE_ADD; 825bf215546Sopenharmony_ci add->U.I.DstReg.File = RC_FILE_TEMPORARY; 826bf215546Sopenharmony_ci add->U.I.DstReg.Index = rc_find_free_temporary(&c->Base); 827bf215546Sopenharmony_ci add->U.I.DstReg.WriteMask = RC_MASK_X; 828bf215546Sopenharmony_ci add->U.I.SrcReg[0] = arl->U.I.SrcReg[0]; 829bf215546Sopenharmony_ci add->U.I.SrcReg[1].File = RC_FILE_CONSTANT; 830bf215546Sopenharmony_ci add->U.I.SrcReg[1].Index = rc_constants_add_immediate_scalar(&c->Base.Program.Constants, 831bf215546Sopenharmony_ci min_offset, &const_swizzle); 832bf215546Sopenharmony_ci add->U.I.SrcReg[1].Swizzle = const_swizzle; 833bf215546Sopenharmony_ci 834bf215546Sopenharmony_ci arl->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 835bf215546Sopenharmony_ci arl->U.I.SrcReg[0].Index = add->U.I.DstReg.Index; 836bf215546Sopenharmony_ci arl->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XXXX; 837bf215546Sopenharmony_ci 838bf215546Sopenharmony_ci /* Rewrite offsets up to and excluding inst. */ 839bf215546Sopenharmony_ci for (inst = arl->Next; inst != end; inst = inst->Next) { 840bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); 841bf215546Sopenharmony_ci 842bf215546Sopenharmony_ci for (unsigned i = 0; i < opcode->NumSrcRegs; i++) 843bf215546Sopenharmony_ci if (inst->U.I.SrcReg[i].RelAddr) 844bf215546Sopenharmony_ci inst->U.I.SrcReg[i].Index -= min_offset; 845bf215546Sopenharmony_ci } 846bf215546Sopenharmony_ci} 847bf215546Sopenharmony_ci 848bf215546Sopenharmony_cistatic void rc_emulate_negative_addressing(struct radeon_compiler *compiler, void *user) 849bf215546Sopenharmony_ci{ 850bf215546Sopenharmony_ci struct r300_vertex_program_compiler * c = (struct r300_vertex_program_compiler*)compiler; 851bf215546Sopenharmony_ci struct rc_instruction *inst, *lastARL = NULL; 852bf215546Sopenharmony_ci int min_offset = 0; 853bf215546Sopenharmony_ci 854bf215546Sopenharmony_ci for (inst = c->Base.Program.Instructions.Next; inst != &c->Base.Program.Instructions; inst = inst->Next) { 855bf215546Sopenharmony_ci const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); 856bf215546Sopenharmony_ci 857bf215546Sopenharmony_ci if (inst->U.I.Opcode == RC_OPCODE_ARL || inst->U.I.Opcode == RC_OPCODE_ARR) { 858bf215546Sopenharmony_ci if (lastARL != NULL && min_offset < 0) 859bf215546Sopenharmony_ci transform_negative_addressing(c, lastARL, inst, min_offset); 860bf215546Sopenharmony_ci 861bf215546Sopenharmony_ci lastARL = inst; 862bf215546Sopenharmony_ci min_offset = 0; 863bf215546Sopenharmony_ci continue; 864bf215546Sopenharmony_ci } 865bf215546Sopenharmony_ci 866bf215546Sopenharmony_ci for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { 867bf215546Sopenharmony_ci if (inst->U.I.SrcReg[i].RelAddr && 868bf215546Sopenharmony_ci inst->U.I.SrcReg[i].Index < 0) { 869bf215546Sopenharmony_ci /* ARL must precede any indirect addressing. */ 870bf215546Sopenharmony_ci if (!lastARL) { 871bf215546Sopenharmony_ci rc_error(&c->Base, "Vertex shader: Found relative addressing without ARL/ARR."); 872bf215546Sopenharmony_ci return; 873bf215546Sopenharmony_ci } 874bf215546Sopenharmony_ci 875bf215546Sopenharmony_ci if (inst->U.I.SrcReg[i].Index < min_offset) 876bf215546Sopenharmony_ci min_offset = inst->U.I.SrcReg[i].Index; 877bf215546Sopenharmony_ci } 878bf215546Sopenharmony_ci } 879bf215546Sopenharmony_ci } 880bf215546Sopenharmony_ci 881bf215546Sopenharmony_ci if (lastARL != NULL && min_offset < 0) 882bf215546Sopenharmony_ci transform_negative_addressing(c, lastARL, inst, min_offset); 883bf215546Sopenharmony_ci} 884bf215546Sopenharmony_ci 885bf215546Sopenharmony_ciconst struct rc_swizzle_caps r300_vertprog_swizzle_caps = { 886bf215546Sopenharmony_ci .IsNative = &swizzle_is_native, 887bf215546Sopenharmony_ci .Split = NULL /* should never be called */ 888bf215546Sopenharmony_ci}; 889bf215546Sopenharmony_ci 890bf215546Sopenharmony_civoid r3xx_compile_vertex_program(struct r300_vertex_program_compiler *c) 891bf215546Sopenharmony_ci{ 892bf215546Sopenharmony_ci int is_r500 = c->Base.is_r500; 893bf215546Sopenharmony_ci int opt = !c->Base.disable_optimizations; 894bf215546Sopenharmony_ci 895bf215546Sopenharmony_ci /* Lists of instruction transformations. */ 896bf215546Sopenharmony_ci struct radeon_program_transformation alu_rewrite_r500[] = { 897bf215546Sopenharmony_ci { &r300_transform_vertex_alu, NULL }, 898bf215546Sopenharmony_ci { &r300_transform_trig_scale_vertex, NULL }, 899bf215546Sopenharmony_ci { NULL, NULL } 900bf215546Sopenharmony_ci }; 901bf215546Sopenharmony_ci 902bf215546Sopenharmony_ci struct radeon_program_transformation alu_rewrite_r300[] = { 903bf215546Sopenharmony_ci { &r300_transform_vertex_alu, NULL }, 904bf215546Sopenharmony_ci { &r300_transform_trig_simple, NULL }, 905bf215546Sopenharmony_ci { NULL, NULL } 906bf215546Sopenharmony_ci }; 907bf215546Sopenharmony_ci 908bf215546Sopenharmony_ci /* Note: These passes have to be done seperately from ALU rewrite, 909bf215546Sopenharmony_ci * otherwise non-native ALU instructions with source conflits 910bf215546Sopenharmony_ci * or non-native modifiers will not be treated properly. 911bf215546Sopenharmony_ci */ 912bf215546Sopenharmony_ci struct radeon_program_transformation emulate_modifiers[] = { 913bf215546Sopenharmony_ci { &transform_nonnative_modifiers, NULL }, 914bf215546Sopenharmony_ci { NULL, NULL } 915bf215546Sopenharmony_ci }; 916bf215546Sopenharmony_ci 917bf215546Sopenharmony_ci struct radeon_program_transformation resolve_src_conflicts[] = { 918bf215546Sopenharmony_ci { &transform_source_conflicts, NULL }, 919bf215546Sopenharmony_ci { NULL, NULL } 920bf215546Sopenharmony_ci }; 921bf215546Sopenharmony_ci 922bf215546Sopenharmony_ci /* List of compiler passes. */ 923bf215546Sopenharmony_ci struct radeon_compiler_pass vs_list[] = { 924bf215546Sopenharmony_ci /* NAME DUMP PREDICATE FUNCTION PARAM */ 925bf215546Sopenharmony_ci {"add artificial outputs", 0, 1, rc_vs_add_artificial_outputs, NULL}, 926bf215546Sopenharmony_ci {"emulate branches", 1, !is_r500, rc_emulate_branches, NULL}, 927bf215546Sopenharmony_ci {"emulate negative addressing", 1, 1, rc_emulate_negative_addressing, NULL}, 928bf215546Sopenharmony_ci {"native rewrite", 1, is_r500, rc_local_transform, alu_rewrite_r500}, 929bf215546Sopenharmony_ci {"native rewrite", 1, !is_r500, rc_local_transform, alu_rewrite_r300}, 930bf215546Sopenharmony_ci {"emulate modifiers", 1, !is_r500, rc_local_transform, emulate_modifiers}, 931bf215546Sopenharmony_ci {"deadcode", 1, opt, rc_dataflow_deadcode, NULL}, 932bf215546Sopenharmony_ci {"dataflow optimize", 1, opt, rc_optimize, NULL}, 933bf215546Sopenharmony_ci /* This pass must be done after optimizations. */ 934bf215546Sopenharmony_ci {"source conflict resolve", 1, 1, rc_local_transform, resolve_src_conflicts}, 935bf215546Sopenharmony_ci {"register allocation", 1, opt, allocate_temporary_registers, NULL}, 936bf215546Sopenharmony_ci {"dead constants", 1, 1, rc_remove_unused_constants, &c->code->constants_remap_table}, 937bf215546Sopenharmony_ci {"lower control flow opcodes", 1, is_r500, rc_vert_fc, NULL}, 938bf215546Sopenharmony_ci {"final code validation", 0, 1, rc_validate_final_shader, NULL}, 939bf215546Sopenharmony_ci {"machine code generation", 0, 1, translate_vertex_program, NULL}, 940bf215546Sopenharmony_ci {"dump machine code", 0, c->Base.Debug & RC_DBG_LOG, r300_vertex_program_dump, NULL}, 941bf215546Sopenharmony_ci {NULL, 0, 0, NULL, NULL} 942bf215546Sopenharmony_ci }; 943bf215546Sopenharmony_ci 944bf215546Sopenharmony_ci c->Base.type = RC_VERTEX_PROGRAM; 945bf215546Sopenharmony_ci c->Base.SwizzleCaps = &r300_vertprog_swizzle_caps; 946bf215546Sopenharmony_ci 947bf215546Sopenharmony_ci rc_run_compiler(&c->Base, vs_list); 948bf215546Sopenharmony_ci 949bf215546Sopenharmony_ci c->code->InputsRead = c->Base.Program.InputsRead; 950bf215546Sopenharmony_ci c->code->OutputsWritten = c->Base.Program.OutputsWritten; 951bf215546Sopenharmony_ci rc_constants_copy(&c->code->constants, &c->Base.Program.Constants); 952bf215546Sopenharmony_ci} 953