1bf215546Sopenharmony_ci/* -*- mesa-c++ -*- 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright (c) 2022 Collabora LTD 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Author: Gert Wollny <gert.wollny@collabora.com> 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 9bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 10bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 11bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 12bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 15bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 16bf215546Sopenharmony_ci * Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 22bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "sfn_peephole.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_cinamespace r600 { 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ciclass PeepholeVisitor : public InstrVisitor { 33bf215546Sopenharmony_cipublic: 34bf215546Sopenharmony_ci void visit(AluInstr *instr) override; 35bf215546Sopenharmony_ci void visit(AluGroup *instr) override; 36bf215546Sopenharmony_ci void visit(TexInstr *instr) override {(void)instr;}; 37bf215546Sopenharmony_ci void visit(ExportInstr *instr) override {(void)instr;} 38bf215546Sopenharmony_ci void visit(FetchInstr *instr) override {(void)instr;} 39bf215546Sopenharmony_ci void visit(Block *instr) override; 40bf215546Sopenharmony_ci void visit(ControlFlowInstr *instr) override {(void)instr;} 41bf215546Sopenharmony_ci void visit(IfInstr *instr) override; 42bf215546Sopenharmony_ci void visit(ScratchIOInstr *instr) override {(void)instr;} 43bf215546Sopenharmony_ci void visit(StreamOutInstr *instr) override {(void)instr;} 44bf215546Sopenharmony_ci void visit(MemRingOutInstr *instr) override {(void)instr;} 45bf215546Sopenharmony_ci void visit(EmitVertexInstr *instr) override {(void)instr;} 46bf215546Sopenharmony_ci void visit(GDSInstr *instr) override {(void)instr;}; 47bf215546Sopenharmony_ci void visit(WriteTFInstr *instr) override {(void)instr;}; 48bf215546Sopenharmony_ci void visit(LDSAtomicInstr *instr) override {(void)instr;}; 49bf215546Sopenharmony_ci void visit(LDSReadInstr *instr) override {(void)instr;}; 50bf215546Sopenharmony_ci void visit(RatInstr *instr) override {(void)instr;}; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci bool src_is_zero(PVirtualValue value); 53bf215546Sopenharmony_ci bool src_is_one(PVirtualValue value); 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci void convert_to_mov(AluInstr *alu, int src_idx); 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci bool progress{false}; 59bf215546Sopenharmony_ci}; 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cibool peephole(Shader& sh) 63bf215546Sopenharmony_ci{ 64bf215546Sopenharmony_ci PeepholeVisitor peephole; 65bf215546Sopenharmony_ci for(auto b : sh.func()) 66bf215546Sopenharmony_ci b->accept(peephole); 67bf215546Sopenharmony_ci return peephole.progress; 68bf215546Sopenharmony_ci} 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_civoid PeepholeVisitor::visit(AluInstr *instr) 71bf215546Sopenharmony_ci{ 72bf215546Sopenharmony_ci switch (instr->opcode()) { 73bf215546Sopenharmony_ci case op2_add: 74bf215546Sopenharmony_ci case op2_add_int: 75bf215546Sopenharmony_ci if (src_is_zero(instr->psrc(0))) 76bf215546Sopenharmony_ci convert_to_mov(instr, 1); 77bf215546Sopenharmony_ci else if (src_is_zero(instr->psrc(1))) 78bf215546Sopenharmony_ci convert_to_mov(instr, 0); 79bf215546Sopenharmony_ci break; 80bf215546Sopenharmony_ci case op2_mul: 81bf215546Sopenharmony_ci case op2_mul_ieee: 82bf215546Sopenharmony_ci if (src_is_one(instr->psrc(0))) 83bf215546Sopenharmony_ci convert_to_mov(instr, 1); 84bf215546Sopenharmony_ci else if (src_is_one(instr->psrc(1))) 85bf215546Sopenharmony_ci convert_to_mov(instr, 0); 86bf215546Sopenharmony_ci break; 87bf215546Sopenharmony_ci case op3_muladd: 88bf215546Sopenharmony_ci case op3_muladd_ieee: 89bf215546Sopenharmony_ci if (src_is_zero(instr->psrc(0)) || 90bf215546Sopenharmony_ci src_is_zero(instr->psrc(1))) 91bf215546Sopenharmony_ci convert_to_mov(instr, 2); 92bf215546Sopenharmony_ci break; 93bf215546Sopenharmony_ci default: 94bf215546Sopenharmony_ci ; 95bf215546Sopenharmony_ci } 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_cibool PeepholeVisitor::src_is_zero(PVirtualValue value) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci if (value->as_inline_const() && 101bf215546Sopenharmony_ci value->as_inline_const()->sel() == ALU_SRC_0) 102bf215546Sopenharmony_ci return true; 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci if (value->as_literal() && 105bf215546Sopenharmony_ci value->as_literal()->value() == 0) 106bf215546Sopenharmony_ci return true; 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci return false; 109bf215546Sopenharmony_ci} 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_cibool PeepholeVisitor::src_is_one(PVirtualValue value) 112bf215546Sopenharmony_ci{ 113bf215546Sopenharmony_ci if (value->as_inline_const() && 114bf215546Sopenharmony_ci value->as_inline_const()->sel() == ALU_SRC_1) 115bf215546Sopenharmony_ci return true; 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci if (value->as_literal() && 118bf215546Sopenharmony_ci value->as_literal()->value() == 0x3f800000) 119bf215546Sopenharmony_ci return true; 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci return false; 122bf215546Sopenharmony_ci} 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_civoid PeepholeVisitor::convert_to_mov(AluInstr *alu, int src_idx) 125bf215546Sopenharmony_ci{ 126bf215546Sopenharmony_ci AluInstr::SrcValues new_src{alu->psrc(src_idx)}; 127bf215546Sopenharmony_ci alu->set_sources(new_src); 128bf215546Sopenharmony_ci alu->set_op(op1_mov); 129bf215546Sopenharmony_ci progress = true; 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_civoid PeepholeVisitor::visit(AluGroup *instr) 134bf215546Sopenharmony_ci{ 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci} 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_civoid PeepholeVisitor::visit(Block *instr) 139bf215546Sopenharmony_ci{ 140bf215546Sopenharmony_ci for (auto& i: *instr) 141bf215546Sopenharmony_ci i->accept(*this); 142bf215546Sopenharmony_ci} 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ciclass ReplaceIfPredicate : public AluInstrVisitor { 145bf215546Sopenharmony_cipublic: 146bf215546Sopenharmony_ci ReplaceIfPredicate(AluInstr *pred): 147bf215546Sopenharmony_ci m_pred(pred) {} 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci using AluInstrVisitor::visit; 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci void visit(AluInstr *alu) override; 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci AluInstr *m_pred; 154bf215546Sopenharmony_ci bool success{false}; 155bf215546Sopenharmony_ci}; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_civoid PeepholeVisitor::visit(IfInstr *instr) 158bf215546Sopenharmony_ci{ 159bf215546Sopenharmony_ci auto pred = instr->predicate(); 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci auto& src1 = pred->src(1); 162bf215546Sopenharmony_ci if (src1.as_inline_const() && 163bf215546Sopenharmony_ci src1.as_inline_const()->sel() == ALU_SRC_0) { 164bf215546Sopenharmony_ci auto src0 = pred->src(0).as_register(); 165bf215546Sopenharmony_ci if (src0 && src0->is_ssa()) { 166bf215546Sopenharmony_ci assert(!src0->parents().empty()); 167bf215546Sopenharmony_ci auto parent = *src0->parents().begin(); 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci ReplaceIfPredicate visitor(pred); 170bf215546Sopenharmony_ci parent->accept(visitor); 171bf215546Sopenharmony_ci progress |= visitor.success; 172bf215546Sopenharmony_ci } 173bf215546Sopenharmony_ci } 174bf215546Sopenharmony_ci} 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_cistatic EAluOp pred_from_op(EAluOp pred_op, EAluOp op) 177bf215546Sopenharmony_ci{ 178bf215546Sopenharmony_ci switch (pred_op) { 179bf215546Sopenharmony_ci case op2_pred_setne_int: 180bf215546Sopenharmony_ci switch (op) { 181bf215546Sopenharmony_ci /* 182bf215546Sopenharmony_ci case op2_setge_dx10 : return op2_pred_setge_int; 183bf215546Sopenharmony_ci case op2_setgt_dx10 : return op2_pred_setgt_int; 184bf215546Sopenharmony_ci case op2_sete_dx10 : return op2_prede_int; 185bf215546Sopenharmony_ci case op2_setne_dx10 : return op2_pred_setne_int; 186bf215546Sopenharmony_ci */ 187bf215546Sopenharmony_ci case op2_setge_int : return op2_pred_setge_int; 188bf215546Sopenharmony_ci case op2_setgt_int : return op2_pred_setgt_int; 189bf215546Sopenharmony_ci case op2_setge_uint : return op2_pred_setge_uint; 190bf215546Sopenharmony_ci case op2_setgt_uint : return op2_pred_setgt_uint; 191bf215546Sopenharmony_ci case op2_sete_int : return op2_prede_int; 192bf215546Sopenharmony_ci case op2_setne_int : return op2_pred_setne_int; 193bf215546Sopenharmony_ci default: 194bf215546Sopenharmony_ci return op0_nop; 195bf215546Sopenharmony_ci } 196bf215546Sopenharmony_ci case op2_prede_int: 197bf215546Sopenharmony_ci switch (op) { 198bf215546Sopenharmony_ci case op2_sete_int : return op2_pred_setne_int; 199bf215546Sopenharmony_ci case op2_setne_int : return op2_prede_int; 200bf215546Sopenharmony_ci default: 201bf215546Sopenharmony_ci return op0_nop; 202bf215546Sopenharmony_ci } 203bf215546Sopenharmony_ci default: 204bf215546Sopenharmony_ci return op0_nop; 205bf215546Sopenharmony_ci } 206bf215546Sopenharmony_ci} 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_civoid ReplaceIfPredicate::visit(AluInstr *alu) 209bf215546Sopenharmony_ci{ 210bf215546Sopenharmony_ci auto new_op = pred_from_op(m_pred->opcode(), alu->opcode()); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci if (new_op == op0_nop) 213bf215546Sopenharmony_ci return; 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci for (auto& s : alu->sources()) { 216bf215546Sopenharmony_ci auto reg = s->as_register(); 217bf215546Sopenharmony_ci /* Protext against propagating 218bf215546Sopenharmony_ci * 219bf215546Sopenharmony_ci * V = COND(R, X) 220bf215546Sopenharmony_ci * R = SOME_OP 221bf215546Sopenharmony_ci * IF (V) 222bf215546Sopenharmony_ci * 223bf215546Sopenharmony_ci * to 224bf215546Sopenharmony_ci * 225bf215546Sopenharmony_ci * R = SOME_OP 226bf215546Sopenharmony_ci * IF (COND(R, X)) 227bf215546Sopenharmony_ci */ 228bf215546Sopenharmony_ci if (reg && !reg->is_ssa()) 229bf215546Sopenharmony_ci return; 230bf215546Sopenharmony_ci } 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci m_pred->set_op(new_op); 233bf215546Sopenharmony_ci m_pred->set_sources(alu->sources()); 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci if (alu->has_alu_flag(alu_src0_abs)) 236bf215546Sopenharmony_ci m_pred->set_alu_flag(alu_src0_abs); 237bf215546Sopenharmony_ci if (alu->has_alu_flag(alu_src1_abs)) 238bf215546Sopenharmony_ci m_pred->set_alu_flag(alu_src1_abs); 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci if (alu->has_alu_flag(alu_src0_neg)) 241bf215546Sopenharmony_ci m_pred->set_alu_flag(alu_src0_neg); 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci if (alu->has_alu_flag(alu_src1_neg)) 244bf215546Sopenharmony_ci m_pred->set_alu_flag(alu_src1_neg); 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci success = true; 247bf215546Sopenharmony_ci} 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci} 250