1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014 Broadcom 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 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * 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 NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/** 25bf215546Sopenharmony_ci * @file vc4_opt_algebraic.c 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci * This is the optimization pass for miscellaneous changes to instructions 28bf215546Sopenharmony_ci * where we can simplify the operation by some knowledge about the specific 29bf215546Sopenharmony_ci * operations. 30bf215546Sopenharmony_ci * 31bf215546Sopenharmony_ci * Mostly this will be a matter of turning things into MOVs so that they can 32bf215546Sopenharmony_ci * later be copy-propagated out. 33bf215546Sopenharmony_ci */ 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include "vc4_qir.h" 36bf215546Sopenharmony_ci#include "util/u_math.h" 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_cistatic bool debug; 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_cistatic void 41bf215546Sopenharmony_cidump_from(struct vc4_compile *c, struct qinst *inst) 42bf215546Sopenharmony_ci{ 43bf215546Sopenharmony_ci if (!debug) 44bf215546Sopenharmony_ci return; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci fprintf(stderr, "optimizing: "); 47bf215546Sopenharmony_ci qir_dump_inst(c, inst); 48bf215546Sopenharmony_ci fprintf(stderr, "\n"); 49bf215546Sopenharmony_ci} 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_cistatic void 52bf215546Sopenharmony_cidump_to(struct vc4_compile *c, struct qinst *inst) 53bf215546Sopenharmony_ci{ 54bf215546Sopenharmony_ci if (!debug) 55bf215546Sopenharmony_ci return; 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci fprintf(stderr, "to: "); 58bf215546Sopenharmony_ci qir_dump_inst(c, inst); 59bf215546Sopenharmony_ci fprintf(stderr, "\n"); 60bf215546Sopenharmony_ci} 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistatic bool 63bf215546Sopenharmony_ciis_constant_value(struct vc4_compile *c, struct qreg reg, 64bf215546Sopenharmony_ci uint32_t val) 65bf215546Sopenharmony_ci{ 66bf215546Sopenharmony_ci if (reg.file == QFILE_UNIF && 67bf215546Sopenharmony_ci !reg.pack && 68bf215546Sopenharmony_ci c->uniform_contents[reg.index] == QUNIFORM_CONSTANT && 69bf215546Sopenharmony_ci c->uniform_data[reg.index] == val) { 70bf215546Sopenharmony_ci return true; 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci if (reg.file == QFILE_SMALL_IMM && reg.index == val) 74bf215546Sopenharmony_ci return true; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci return false; 77bf215546Sopenharmony_ci} 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_cistatic bool 80bf215546Sopenharmony_ciis_zero(struct vc4_compile *c, struct qreg reg) 81bf215546Sopenharmony_ci{ 82bf215546Sopenharmony_ci reg = qir_follow_movs(c, reg); 83bf215546Sopenharmony_ci return is_constant_value(c, reg, 0); 84bf215546Sopenharmony_ci} 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_cistatic bool 87bf215546Sopenharmony_ciis_1f(struct vc4_compile *c, struct qreg reg) 88bf215546Sopenharmony_ci{ 89bf215546Sopenharmony_ci reg = qir_follow_movs(c, reg); 90bf215546Sopenharmony_ci return is_constant_value(c, reg, fui(1.0)); 91bf215546Sopenharmony_ci} 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_cistatic void 94bf215546Sopenharmony_cireplace_with_mov(struct vc4_compile *c, struct qinst *inst, struct qreg arg) 95bf215546Sopenharmony_ci{ 96bf215546Sopenharmony_ci dump_from(c, inst); 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci inst->src[0] = arg; 99bf215546Sopenharmony_ci if (qir_has_implicit_tex_uniform(inst)) 100bf215546Sopenharmony_ci inst->src[1] = inst->src[qir_get_tex_uniform_src(inst)]; 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci if (qir_is_mul(inst)) 103bf215546Sopenharmony_ci inst->op = QOP_MMOV; 104bf215546Sopenharmony_ci else if (qir_is_float_input(inst)) 105bf215546Sopenharmony_ci inst->op = QOP_FMOV; 106bf215546Sopenharmony_ci else 107bf215546Sopenharmony_ci inst->op = QOP_MOV; 108bf215546Sopenharmony_ci dump_to(c, inst); 109bf215546Sopenharmony_ci} 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_cistatic bool 112bf215546Sopenharmony_cireplace_x_0_with_x(struct vc4_compile *c, 113bf215546Sopenharmony_ci struct qinst *inst, 114bf215546Sopenharmony_ci int arg) 115bf215546Sopenharmony_ci{ 116bf215546Sopenharmony_ci if (!is_zero(c, inst->src[arg])) 117bf215546Sopenharmony_ci return false; 118bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[1 - arg]); 119bf215546Sopenharmony_ci return true; 120bf215546Sopenharmony_ci} 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_cistatic bool 123bf215546Sopenharmony_cireplace_x_0_with_0(struct vc4_compile *c, 124bf215546Sopenharmony_ci struct qinst *inst, 125bf215546Sopenharmony_ci int arg) 126bf215546Sopenharmony_ci{ 127bf215546Sopenharmony_ci if (!is_zero(c, inst->src[arg])) 128bf215546Sopenharmony_ci return false; 129bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[arg]); 130bf215546Sopenharmony_ci return true; 131bf215546Sopenharmony_ci} 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_cistatic bool 134bf215546Sopenharmony_cifmul_replace_one(struct vc4_compile *c, 135bf215546Sopenharmony_ci struct qinst *inst, 136bf215546Sopenharmony_ci int arg) 137bf215546Sopenharmony_ci{ 138bf215546Sopenharmony_ci if (!is_1f(c, inst->src[arg])) 139bf215546Sopenharmony_ci return false; 140bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[1 - arg]); 141bf215546Sopenharmony_ci return true; 142bf215546Sopenharmony_ci} 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_cibool 145bf215546Sopenharmony_ciqir_opt_algebraic(struct vc4_compile *c) 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci bool progress = false; 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci qir_for_each_inst_inorder(inst, c) { 150bf215546Sopenharmony_ci switch (inst->op) { 151bf215546Sopenharmony_ci case QOP_FMIN: 152bf215546Sopenharmony_ci if (is_1f(c, inst->src[1]) && 153bf215546Sopenharmony_ci inst->src[0].pack >= QPU_UNPACK_8D_REP && 154bf215546Sopenharmony_ci inst->src[0].pack <= QPU_UNPACK_8D) { 155bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[0]); 156bf215546Sopenharmony_ci progress = true; 157bf215546Sopenharmony_ci } 158bf215546Sopenharmony_ci break; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci case QOP_FMAX: 161bf215546Sopenharmony_ci if (is_zero(c, inst->src[1]) && 162bf215546Sopenharmony_ci inst->src[0].pack >= QPU_UNPACK_8D_REP && 163bf215546Sopenharmony_ci inst->src[0].pack <= QPU_UNPACK_8D) { 164bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[0]); 165bf215546Sopenharmony_ci progress = true; 166bf215546Sopenharmony_ci } 167bf215546Sopenharmony_ci break; 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci case QOP_FSUB: 170bf215546Sopenharmony_ci case QOP_SUB: 171bf215546Sopenharmony_ci if (is_zero(c, inst->src[1])) { 172bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[0]); 173bf215546Sopenharmony_ci progress = true; 174bf215546Sopenharmony_ci } 175bf215546Sopenharmony_ci break; 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci case QOP_ADD: 178bf215546Sopenharmony_ci /* Kernel validation requires that we use an actual 179bf215546Sopenharmony_ci * add instruction. 180bf215546Sopenharmony_ci */ 181bf215546Sopenharmony_ci if (inst->dst.file != QFILE_TEX_S_DIRECT && 182bf215546Sopenharmony_ci (replace_x_0_with_x(c, inst, 0) || 183bf215546Sopenharmony_ci replace_x_0_with_x(c, inst, 1))) { 184bf215546Sopenharmony_ci progress = true; 185bf215546Sopenharmony_ci break; 186bf215546Sopenharmony_ci } 187bf215546Sopenharmony_ci break; 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci case QOP_FADD: 190bf215546Sopenharmony_ci if (replace_x_0_with_x(c, inst, 0) || 191bf215546Sopenharmony_ci replace_x_0_with_x(c, inst, 1)) { 192bf215546Sopenharmony_ci progress = true; 193bf215546Sopenharmony_ci break; 194bf215546Sopenharmony_ci } 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci /* FADD(a, FSUB(0, b)) -> FSUB(a, b) */ 197bf215546Sopenharmony_ci if (inst->src[1].file == QFILE_TEMP && 198bf215546Sopenharmony_ci c->defs[inst->src[1].index] && 199bf215546Sopenharmony_ci c->defs[inst->src[1].index]->op == QOP_FSUB) { 200bf215546Sopenharmony_ci struct qinst *fsub = c->defs[inst->src[1].index]; 201bf215546Sopenharmony_ci if (is_zero(c, fsub->src[0])) { 202bf215546Sopenharmony_ci dump_from(c, inst); 203bf215546Sopenharmony_ci inst->op = QOP_FSUB; 204bf215546Sopenharmony_ci inst->src[1] = fsub->src[1]; 205bf215546Sopenharmony_ci progress = true; 206bf215546Sopenharmony_ci dump_to(c, inst); 207bf215546Sopenharmony_ci break; 208bf215546Sopenharmony_ci } 209bf215546Sopenharmony_ci } 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci /* FADD(FSUB(0, b), a) -> FSUB(a, b) */ 212bf215546Sopenharmony_ci if (inst->src[0].file == QFILE_TEMP && 213bf215546Sopenharmony_ci c->defs[inst->src[0].index] && 214bf215546Sopenharmony_ci c->defs[inst->src[0].index]->op == QOP_FSUB) { 215bf215546Sopenharmony_ci struct qinst *fsub = c->defs[inst->src[0].index]; 216bf215546Sopenharmony_ci if (is_zero(c, fsub->src[0])) { 217bf215546Sopenharmony_ci dump_from(c, inst); 218bf215546Sopenharmony_ci inst->op = QOP_FSUB; 219bf215546Sopenharmony_ci inst->src[0] = inst->src[1]; 220bf215546Sopenharmony_ci inst->src[1] = fsub->src[1]; 221bf215546Sopenharmony_ci dump_to(c, inst); 222bf215546Sopenharmony_ci progress = true; 223bf215546Sopenharmony_ci break; 224bf215546Sopenharmony_ci } 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci break; 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci case QOP_FMUL: 229bf215546Sopenharmony_ci if (!inst->dst.pack && 230bf215546Sopenharmony_ci (replace_x_0_with_0(c, inst, 0) || 231bf215546Sopenharmony_ci replace_x_0_with_0(c, inst, 1) || 232bf215546Sopenharmony_ci fmul_replace_one(c, inst, 0) || 233bf215546Sopenharmony_ci fmul_replace_one(c, inst, 1))) { 234bf215546Sopenharmony_ci progress = true; 235bf215546Sopenharmony_ci break; 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci break; 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci case QOP_MUL24: 240bf215546Sopenharmony_ci if (!inst->dst.pack && 241bf215546Sopenharmony_ci (replace_x_0_with_0(c, inst, 0) || 242bf215546Sopenharmony_ci replace_x_0_with_0(c, inst, 1))) { 243bf215546Sopenharmony_ci progress = true; 244bf215546Sopenharmony_ci break; 245bf215546Sopenharmony_ci } 246bf215546Sopenharmony_ci break; 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci case QOP_AND: 249bf215546Sopenharmony_ci if (replace_x_0_with_0(c, inst, 0) || 250bf215546Sopenharmony_ci replace_x_0_with_0(c, inst, 1)) { 251bf215546Sopenharmony_ci progress = true; 252bf215546Sopenharmony_ci break; 253bf215546Sopenharmony_ci } 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci if (is_constant_value(c, inst->src[0], ~0)) { 256bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[1]); 257bf215546Sopenharmony_ci progress = true; 258bf215546Sopenharmony_ci break; 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci if (is_constant_value(c, inst->src[1], ~0)) { 261bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[0]); 262bf215546Sopenharmony_ci progress = true; 263bf215546Sopenharmony_ci break; 264bf215546Sopenharmony_ci } 265bf215546Sopenharmony_ci break; 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci case QOP_OR: 268bf215546Sopenharmony_ci if (replace_x_0_with_x(c, inst, 0) || 269bf215546Sopenharmony_ci replace_x_0_with_x(c, inst, 1)) { 270bf215546Sopenharmony_ci progress = true; 271bf215546Sopenharmony_ci break; 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci break; 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci case QOP_RCP: 276bf215546Sopenharmony_ci if (is_1f(c, inst->src[0])) { 277bf215546Sopenharmony_ci replace_with_mov(c, inst, inst->src[0]); 278bf215546Sopenharmony_ci progress = true; 279bf215546Sopenharmony_ci break; 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci break; 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci default: 284bf215546Sopenharmony_ci break; 285bf215546Sopenharmony_ci } 286bf215546Sopenharmony_ci } 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci return progress; 289bf215546Sopenharmony_ci} 290