1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (c) 2017 Lima Project 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, sub license, 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 12bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 13bf215546Sopenharmony_ci * of the 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 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 21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci */ 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci#include "util/bitscan.h" 26bf215546Sopenharmony_ci#include "util/ralloc.h" 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "ppir.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_cistatic bool ppir_lower_const(ppir_block *block, ppir_node *node) 31bf215546Sopenharmony_ci{ 32bf215546Sopenharmony_ci if (ppir_node_is_root(node)) { 33bf215546Sopenharmony_ci ppir_node_delete(node); 34bf215546Sopenharmony_ci return true; 35bf215546Sopenharmony_ci } 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci assert(ppir_node_has_single_succ(node)); 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci ppir_node *succ = ppir_node_first_succ(node); 40bf215546Sopenharmony_ci ppir_dest *dest = ppir_node_get_dest(node); 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci switch (succ->type) { 43bf215546Sopenharmony_ci case ppir_node_type_alu: 44bf215546Sopenharmony_ci case ppir_node_type_branch: 45bf215546Sopenharmony_ci /* ALU and branch can consume consts directly */ 46bf215546Sopenharmony_ci dest->type = ppir_target_pipeline; 47bf215546Sopenharmony_ci /* Reg will be updated in node_to_instr later */ 48bf215546Sopenharmony_ci dest->pipeline = ppir_pipeline_reg_const0; 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci /* single succ can still have multiple references to this node */ 51bf215546Sopenharmony_ci for (int i = 0; i < ppir_node_get_src_num(succ); i++) { 52bf215546Sopenharmony_ci ppir_src *src = ppir_node_get_src(succ, i); 53bf215546Sopenharmony_ci if (src && src->node == node) { 54bf215546Sopenharmony_ci src->type = ppir_target_pipeline; 55bf215546Sopenharmony_ci src->pipeline = ppir_pipeline_reg_const0; 56bf215546Sopenharmony_ci } 57bf215546Sopenharmony_ci } 58bf215546Sopenharmony_ci return true; 59bf215546Sopenharmony_ci default: 60bf215546Sopenharmony_ci /* Create a move for everyone else */ 61bf215546Sopenharmony_ci break; 62bf215546Sopenharmony_ci } 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci ppir_node *move = ppir_node_insert_mov(node); 65bf215546Sopenharmony_ci if (unlikely(!move)) 66bf215546Sopenharmony_ci return false; 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci ppir_debug("lower const create move %d for %d\n", 69bf215546Sopenharmony_ci move->index, node->index); 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci /* Need to be careful with changing src/dst type here: 72bf215546Sopenharmony_ci * it has to be done *after* successors have their children 73bf215546Sopenharmony_ci * replaced, otherwise ppir_node_replace_child() won't find 74bf215546Sopenharmony_ci * matching src/dst and as result won't work 75bf215546Sopenharmony_ci */ 76bf215546Sopenharmony_ci ppir_src *mov_src = ppir_node_get_src(move, 0); 77bf215546Sopenharmony_ci mov_src->type = dest->type = ppir_target_pipeline; 78bf215546Sopenharmony_ci mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_const0; 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci return true; 81bf215546Sopenharmony_ci} 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_cistatic bool ppir_lower_swap_args(ppir_block *block, ppir_node *node) 84bf215546Sopenharmony_ci{ 85bf215546Sopenharmony_ci /* swapped op must be the next op */ 86bf215546Sopenharmony_ci node->op++; 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci assert(node->type == ppir_node_type_alu); 89bf215546Sopenharmony_ci ppir_alu_node *alu = ppir_node_to_alu(node); 90bf215546Sopenharmony_ci assert(alu->num_src == 2); 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci ppir_src tmp = alu->src[0]; 93bf215546Sopenharmony_ci alu->src[0] = alu->src[1]; 94bf215546Sopenharmony_ci alu->src[1] = tmp; 95bf215546Sopenharmony_ci return true; 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_cistatic bool ppir_lower_load(ppir_block *block, ppir_node *node) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci ppir_dest *dest = ppir_node_get_dest(node); 101bf215546Sopenharmony_ci if (ppir_node_is_root(node) && dest->type == ppir_target_ssa) { 102bf215546Sopenharmony_ci ppir_node_delete(node); 103bf215546Sopenharmony_ci return true; 104bf215546Sopenharmony_ci } 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci /* load can have multiple successors in case if we duplicated load node 107bf215546Sopenharmony_ci * that has load node in source 108bf215546Sopenharmony_ci */ 109bf215546Sopenharmony_ci if ((ppir_node_has_single_src_succ(node) || ppir_node_is_root(node)) && 110bf215546Sopenharmony_ci dest->type != ppir_target_register) { 111bf215546Sopenharmony_ci ppir_node *succ = ppir_node_first_succ(node); 112bf215546Sopenharmony_ci switch (succ->type) { 113bf215546Sopenharmony_ci case ppir_node_type_alu: 114bf215546Sopenharmony_ci case ppir_node_type_branch: { 115bf215546Sopenharmony_ci /* single succ can still have multiple references to this node */ 116bf215546Sopenharmony_ci for (int i = 0; i < ppir_node_get_src_num(succ); i++) { 117bf215546Sopenharmony_ci ppir_src *src = ppir_node_get_src(succ, i); 118bf215546Sopenharmony_ci if (src && src->node == node) { 119bf215546Sopenharmony_ci /* Can consume uniforms directly */ 120bf215546Sopenharmony_ci src->type = dest->type = ppir_target_pipeline; 121bf215546Sopenharmony_ci src->pipeline = dest->pipeline = ppir_pipeline_reg_uniform; 122bf215546Sopenharmony_ci } 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci return true; 125bf215546Sopenharmony_ci } 126bf215546Sopenharmony_ci default: 127bf215546Sopenharmony_ci /* Create mov for everyone else */ 128bf215546Sopenharmony_ci break; 129bf215546Sopenharmony_ci } 130bf215546Sopenharmony_ci } 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci ppir_node *move = ppir_node_insert_mov(node); 133bf215546Sopenharmony_ci if (unlikely(!move)) 134bf215546Sopenharmony_ci return false; 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci ppir_src *mov_src = ppir_node_get_src(move, 0); 137bf215546Sopenharmony_ci mov_src->type = dest->type = ppir_target_pipeline; 138bf215546Sopenharmony_ci mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_uniform; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci return true; 141bf215546Sopenharmony_ci} 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_cistatic bool ppir_lower_ddxy(ppir_block *block, ppir_node *node) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci assert(node->type == ppir_node_type_alu); 146bf215546Sopenharmony_ci ppir_alu_node *alu = ppir_node_to_alu(node); 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci alu->src[1] = alu->src[0]; 149bf215546Sopenharmony_ci if (node->op == ppir_op_ddx) 150bf215546Sopenharmony_ci alu->src[1].negate = !alu->src[1].negate; 151bf215546Sopenharmony_ci else if (node->op == ppir_op_ddy) 152bf215546Sopenharmony_ci alu->src[0].negate = !alu->src[0].negate; 153bf215546Sopenharmony_ci else 154bf215546Sopenharmony_ci assert(0); 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci alu->num_src = 2; 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci return true; 159bf215546Sopenharmony_ci} 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_cistatic bool ppir_lower_texture(ppir_block *block, ppir_node *node) 162bf215546Sopenharmony_ci{ 163bf215546Sopenharmony_ci ppir_dest *dest = ppir_node_get_dest(node); 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci if (ppir_node_has_single_succ(node) && dest->type == ppir_target_ssa) { 166bf215546Sopenharmony_ci ppir_node *succ = ppir_node_first_succ(node); 167bf215546Sopenharmony_ci dest->type = ppir_target_pipeline; 168bf215546Sopenharmony_ci dest->pipeline = ppir_pipeline_reg_sampler; 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci for (int i = 0; i < ppir_node_get_src_num(succ); i++) { 171bf215546Sopenharmony_ci ppir_src *src = ppir_node_get_src(succ, i); 172bf215546Sopenharmony_ci if (src && src->node == node) { 173bf215546Sopenharmony_ci src->type = ppir_target_pipeline; 174bf215546Sopenharmony_ci src->pipeline = ppir_pipeline_reg_sampler; 175bf215546Sopenharmony_ci } 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci return true; 178bf215546Sopenharmony_ci } 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci /* Create move node as fallback */ 181bf215546Sopenharmony_ci ppir_node *move = ppir_node_insert_mov(node); 182bf215546Sopenharmony_ci if (unlikely(!move)) 183bf215546Sopenharmony_ci return false; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci ppir_debug("lower texture create move %d for %d\n", 186bf215546Sopenharmony_ci move->index, node->index); 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci ppir_src *mov_src = ppir_node_get_src(move, 0); 189bf215546Sopenharmony_ci mov_src->type = dest->type = ppir_target_pipeline; 190bf215546Sopenharmony_ci mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_sampler; 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci return true; 193bf215546Sopenharmony_ci} 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci/* Check if the select condition and ensure it can be inserted to 196bf215546Sopenharmony_ci * the scalar mul slot */ 197bf215546Sopenharmony_cistatic bool ppir_lower_select(ppir_block *block, ppir_node *node) 198bf215546Sopenharmony_ci{ 199bf215546Sopenharmony_ci ppir_alu_node *alu = ppir_node_to_alu(node); 200bf215546Sopenharmony_ci ppir_src *src0 = &alu->src[0]; 201bf215546Sopenharmony_ci ppir_src *src1 = &alu->src[1]; 202bf215546Sopenharmony_ci ppir_src *src2 = &alu->src[2]; 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci /* If the condition is already an alu scalar whose only successor 205bf215546Sopenharmony_ci * is the select node, just turn it into pipeline output. */ 206bf215546Sopenharmony_ci /* The (src2->node == cond) case is a tricky exception. 207bf215546Sopenharmony_ci * The reason is that we must force cond to output to ^fmul -- but 208bf215546Sopenharmony_ci * then it no longer writes to a register and it is impossible to 209bf215546Sopenharmony_ci * reference ^fmul in src2. So in that exceptional case, also fall 210bf215546Sopenharmony_ci * back to the mov. */ 211bf215546Sopenharmony_ci ppir_node *cond = src0->node; 212bf215546Sopenharmony_ci if (cond && 213bf215546Sopenharmony_ci cond->type == ppir_node_type_alu && 214bf215546Sopenharmony_ci ppir_node_has_single_succ(cond) && 215bf215546Sopenharmony_ci ppir_target_is_scalar(ppir_node_get_dest(cond)) && 216bf215546Sopenharmony_ci ppir_node_schedulable_slot(cond, PPIR_INSTR_SLOT_ALU_SCL_MUL) && 217bf215546Sopenharmony_ci src2->node != cond) { 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci ppir_dest *cond_dest = ppir_node_get_dest(cond); 220bf215546Sopenharmony_ci cond_dest->type = ppir_target_pipeline; 221bf215546Sopenharmony_ci cond_dest->pipeline = ppir_pipeline_reg_fmul; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci ppir_node_target_assign(src0, cond); 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci /* src1 could also be a reference from the same node as 226bf215546Sopenharmony_ci * the condition, so update it in that case. */ 227bf215546Sopenharmony_ci if (src1->node && src1->node == cond) 228bf215546Sopenharmony_ci ppir_node_target_assign(src1, cond); 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci return true; 231bf215546Sopenharmony_ci } 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci /* If the condition can't be used for any reason, insert a mov 234bf215546Sopenharmony_ci * so that the condition can end up in ^fmul */ 235bf215546Sopenharmony_ci ppir_node *move = ppir_node_create(block, ppir_op_mov, -1, 0); 236bf215546Sopenharmony_ci if (!move) 237bf215546Sopenharmony_ci return false; 238bf215546Sopenharmony_ci list_addtail(&move->list, &node->list); 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci ppir_alu_node *move_alu = ppir_node_to_alu(move); 241bf215546Sopenharmony_ci ppir_src *move_src = move_alu->src; 242bf215546Sopenharmony_ci move_src->type = src0->type; 243bf215546Sopenharmony_ci move_src->ssa = src0->ssa; 244bf215546Sopenharmony_ci move_src->swizzle[0] = src0->swizzle[0]; 245bf215546Sopenharmony_ci move_alu->num_src = 1; 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci ppir_dest *move_dest = &move_alu->dest; 248bf215546Sopenharmony_ci move_dest->type = ppir_target_pipeline; 249bf215546Sopenharmony_ci move_dest->pipeline = ppir_pipeline_reg_fmul; 250bf215546Sopenharmony_ci move_dest->write_mask = 1; 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci ppir_node *pred = src0->node; 253bf215546Sopenharmony_ci ppir_dep *dep = ppir_dep_for_pred(node, pred); 254bf215546Sopenharmony_ci if (dep) 255bf215546Sopenharmony_ci ppir_node_replace_pred(dep, move); 256bf215546Sopenharmony_ci else 257bf215546Sopenharmony_ci ppir_node_add_dep(node, move, ppir_dep_src); 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci /* pred can be a register */ 260bf215546Sopenharmony_ci if (pred) 261bf215546Sopenharmony_ci ppir_node_add_dep(move, pred, ppir_dep_src); 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci ppir_node_target_assign(src0, move); 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci /* src1 could also be a reference from the same node as 266bf215546Sopenharmony_ci * the condition, so update it in that case. */ 267bf215546Sopenharmony_ci if (src1->node && src1->node == pred) 268bf215546Sopenharmony_ci ppir_node_target_assign(src1, move); 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_ci return true; 271bf215546Sopenharmony_ci} 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_cistatic bool ppir_lower_trunc(ppir_block *block, ppir_node *node) 274bf215546Sopenharmony_ci{ 275bf215546Sopenharmony_ci /* Turn it into a mov with a round to integer output modifier */ 276bf215546Sopenharmony_ci ppir_alu_node *alu = ppir_node_to_alu(node); 277bf215546Sopenharmony_ci ppir_dest *move_dest = &alu->dest; 278bf215546Sopenharmony_ci move_dest->modifier = ppir_outmod_round; 279bf215546Sopenharmony_ci node->op = ppir_op_mov; 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci return true; 282bf215546Sopenharmony_ci} 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_cistatic bool ppir_lower_abs(ppir_block *block, ppir_node *node) 285bf215546Sopenharmony_ci{ 286bf215546Sopenharmony_ci /* Turn it into a mov and set the absolute modifier */ 287bf215546Sopenharmony_ci ppir_alu_node *alu = ppir_node_to_alu(node); 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci assert(alu->num_src == 1); 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci alu->src[0].absolute = true; 292bf215546Sopenharmony_ci alu->src[0].negate = false; 293bf215546Sopenharmony_ci node->op = ppir_op_mov; 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci return true; 296bf215546Sopenharmony_ci} 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_cistatic bool ppir_lower_neg(ppir_block *block, ppir_node *node) 299bf215546Sopenharmony_ci{ 300bf215546Sopenharmony_ci /* Turn it into a mov and set the negate modifier */ 301bf215546Sopenharmony_ci ppir_alu_node *alu = ppir_node_to_alu(node); 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci assert(alu->num_src == 1); 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci alu->src[0].negate = !alu->src[0].negate; 306bf215546Sopenharmony_ci node->op = ppir_op_mov; 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci return true; 309bf215546Sopenharmony_ci} 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_cistatic bool ppir_lower_sat(ppir_block *block, ppir_node *node) 312bf215546Sopenharmony_ci{ 313bf215546Sopenharmony_ci /* Turn it into a mov with the saturate output modifier */ 314bf215546Sopenharmony_ci ppir_alu_node *alu = ppir_node_to_alu(node); 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci assert(alu->num_src == 1); 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci ppir_dest *move_dest = &alu->dest; 319bf215546Sopenharmony_ci move_dest->modifier = ppir_outmod_clamp_fraction; 320bf215546Sopenharmony_ci node->op = ppir_op_mov; 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ci return true; 323bf215546Sopenharmony_ci} 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_cistatic bool ppir_lower_branch_merge_condition(ppir_block *block, ppir_node *node) 326bf215546Sopenharmony_ci{ 327bf215546Sopenharmony_ci /* Check if we can merge a condition with a branch instruction, 328bf215546Sopenharmony_ci * removing the need for a select instruction */ 329bf215546Sopenharmony_ci assert(node->type == ppir_node_type_branch); 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci if (!ppir_node_has_single_pred(node)) 332bf215546Sopenharmony_ci return false; 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_ci ppir_node *pred = ppir_node_first_pred(node); 335bf215546Sopenharmony_ci assert(pred); 336bf215546Sopenharmony_ci 337bf215546Sopenharmony_ci if (pred->type != ppir_node_type_alu) 338bf215546Sopenharmony_ci return false; 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci switch (pred->op) 341bf215546Sopenharmony_ci { 342bf215546Sopenharmony_ci case ppir_op_lt: 343bf215546Sopenharmony_ci case ppir_op_gt: 344bf215546Sopenharmony_ci case ppir_op_le: 345bf215546Sopenharmony_ci case ppir_op_ge: 346bf215546Sopenharmony_ci case ppir_op_eq: 347bf215546Sopenharmony_ci case ppir_op_ne: 348bf215546Sopenharmony_ci break; 349bf215546Sopenharmony_ci default: 350bf215546Sopenharmony_ci return false; 351bf215546Sopenharmony_ci } 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci ppir_dest *dest = ppir_node_get_dest(pred); 354bf215546Sopenharmony_ci if (!ppir_node_has_single_succ(pred) || dest->type != ppir_target_ssa) 355bf215546Sopenharmony_ci return false; 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci ppir_alu_node *cond = ppir_node_to_alu(pred); 358bf215546Sopenharmony_ci /* branch can't reference pipeline registers */ 359bf215546Sopenharmony_ci if (cond->src[0].type == ppir_target_pipeline || 360bf215546Sopenharmony_ci cond->src[1].type == ppir_target_pipeline) 361bf215546Sopenharmony_ci return false; 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci /* branch can't use flags */ 364bf215546Sopenharmony_ci if (cond->src[0].negate || cond->src[0].absolute || 365bf215546Sopenharmony_ci cond->src[1].negate || cond->src[1].absolute) 366bf215546Sopenharmony_ci return false; 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci /* at this point, it can be successfully be replaced. */ 369bf215546Sopenharmony_ci ppir_branch_node *branch = ppir_node_to_branch(node); 370bf215546Sopenharmony_ci switch (pred->op) 371bf215546Sopenharmony_ci { 372bf215546Sopenharmony_ci case ppir_op_le: 373bf215546Sopenharmony_ci branch->cond_gt = true; 374bf215546Sopenharmony_ci break; 375bf215546Sopenharmony_ci case ppir_op_lt: 376bf215546Sopenharmony_ci branch->cond_eq = true; 377bf215546Sopenharmony_ci branch->cond_gt = true; 378bf215546Sopenharmony_ci break; 379bf215546Sopenharmony_ci case ppir_op_ge: 380bf215546Sopenharmony_ci branch->cond_lt = true; 381bf215546Sopenharmony_ci break; 382bf215546Sopenharmony_ci case ppir_op_gt: 383bf215546Sopenharmony_ci branch->cond_eq = true; 384bf215546Sopenharmony_ci branch->cond_lt = true; 385bf215546Sopenharmony_ci break; 386bf215546Sopenharmony_ci case ppir_op_eq: 387bf215546Sopenharmony_ci branch->cond_lt = true; 388bf215546Sopenharmony_ci branch->cond_gt = true; 389bf215546Sopenharmony_ci break; 390bf215546Sopenharmony_ci case ppir_op_ne: 391bf215546Sopenharmony_ci branch->cond_eq = true; 392bf215546Sopenharmony_ci break; 393bf215546Sopenharmony_ci default: 394bf215546Sopenharmony_ci assert(0); 395bf215546Sopenharmony_ci break; 396bf215546Sopenharmony_ci } 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci assert(cond->num_src == 2); 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci branch->num_src = 2; 401bf215546Sopenharmony_ci branch->src[0] = cond->src[0]; 402bf215546Sopenharmony_ci branch->src[1] = cond->src[1]; 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci /* for all nodes before the condition */ 405bf215546Sopenharmony_ci ppir_node_foreach_pred_safe(pred, dep) { 406bf215546Sopenharmony_ci /* insert the branch node as successor */ 407bf215546Sopenharmony_ci ppir_node *p = dep->pred; 408bf215546Sopenharmony_ci ppir_node_remove_dep(dep); 409bf215546Sopenharmony_ci ppir_node_add_dep(node, p, ppir_dep_src); 410bf215546Sopenharmony_ci } 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci ppir_node_delete(pred); 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci return true; 415bf215546Sopenharmony_ci} 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_cistatic bool ppir_lower_branch(ppir_block *block, ppir_node *node) 418bf215546Sopenharmony_ci{ 419bf215546Sopenharmony_ci ppir_branch_node *branch = ppir_node_to_branch(node); 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci /* Unconditional branch */ 422bf215546Sopenharmony_ci if (branch->num_src == 0) 423bf215546Sopenharmony_ci return true; 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ci /* Check if we can merge a condition with the branch */ 426bf215546Sopenharmony_ci if (ppir_lower_branch_merge_condition(block, node)) 427bf215546Sopenharmony_ci return true; 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci /* If the condition cannot be merged, fall back to a 430bf215546Sopenharmony_ci * comparison against zero */ 431bf215546Sopenharmony_ci ppir_const_node *zero = ppir_node_create(block, ppir_op_const, -1, 0); 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci if (!zero) 434bf215546Sopenharmony_ci return false; 435bf215546Sopenharmony_ci 436bf215546Sopenharmony_ci zero->constant.value[0].f = 0; 437bf215546Sopenharmony_ci zero->constant.num = 1; 438bf215546Sopenharmony_ci zero->dest.type = ppir_target_pipeline; 439bf215546Sopenharmony_ci zero->dest.pipeline = ppir_pipeline_reg_const0; 440bf215546Sopenharmony_ci zero->dest.ssa.num_components = 1; 441bf215546Sopenharmony_ci zero->dest.write_mask = 0x01; 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_ci ppir_node_target_assign(&branch->src[1], &zero->node); 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci if (branch->negate) 446bf215546Sopenharmony_ci branch->cond_eq = true; 447bf215546Sopenharmony_ci else { 448bf215546Sopenharmony_ci branch->cond_gt = true; 449bf215546Sopenharmony_ci branch->cond_lt = true; 450bf215546Sopenharmony_ci } 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci branch->num_src = 2; 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci ppir_node_add_dep(&branch->node, &zero->node, ppir_dep_src); 455bf215546Sopenharmony_ci list_addtail(&zero->node.list, &node->list); 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci return true; 458bf215546Sopenharmony_ci} 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_cistatic bool ppir_lower_accum(ppir_block *block, ppir_node *node) 461bf215546Sopenharmony_ci{ 462bf215546Sopenharmony_ci /* If the last argument of a node placed in PPIR_INSTR_SLOT_ALU_SCL_ADD 463bf215546Sopenharmony_ci * (or PPIR_INSTR_SLOT_ALU_VEC_ADD) is placed in 464bf215546Sopenharmony_ci * PPIR_INSTR_SLOT_ALU_SCL_MUL (or PPIR_INSTR_SLOT_ALU_VEC_MUL) we cannot 465bf215546Sopenharmony_ci * save a register (and an instruction) by using a pipeline register. 466bf215546Sopenharmony_ci * Therefore it is interesting to make sure arguments of that type are 467bf215546Sopenharmony_ci * the first argument by swapping arguments (if possible) */ 468bf215546Sopenharmony_ci ppir_alu_node *alu = ppir_node_to_alu(node); 469bf215546Sopenharmony_ci 470bf215546Sopenharmony_ci assert(alu->num_src >= 2); 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_ci if (alu->src[0].type == ppir_target_pipeline) 473bf215546Sopenharmony_ci return true; 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci if (alu->src[0].type == ppir_target_ssa) { 476bf215546Sopenharmony_ci int *src_0_slots = ppir_op_infos[alu->src[0].node->op].slots; 477bf215546Sopenharmony_ci if (src_0_slots) { 478bf215546Sopenharmony_ci for (int i = 0; src_0_slots[i] != PPIR_INSTR_SLOT_END; i++) { 479bf215546Sopenharmony_ci if ((src_0_slots[i] == PPIR_INSTR_SLOT_ALU_SCL_MUL) || 480bf215546Sopenharmony_ci (src_0_slots[i] == PPIR_INSTR_SLOT_ALU_VEC_MUL)) { 481bf215546Sopenharmony_ci return true; 482bf215546Sopenharmony_ci } 483bf215546Sopenharmony_ci } 484bf215546Sopenharmony_ci } 485bf215546Sopenharmony_ci } 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_ci int src_to_swap = -1; 488bf215546Sopenharmony_ci for (int j = 1; j < alu->num_src; j++) { 489bf215546Sopenharmony_ci if (alu->src[j].type != ppir_target_ssa) 490bf215546Sopenharmony_ci continue; 491bf215546Sopenharmony_ci int *src_slots = ppir_op_infos[alu->src[j].node->op].slots; 492bf215546Sopenharmony_ci if (!src_slots) 493bf215546Sopenharmony_ci continue; 494bf215546Sopenharmony_ci for (int i = 0; src_slots[i] != PPIR_INSTR_SLOT_END; i++) { 495bf215546Sopenharmony_ci if ((src_slots[i] == PPIR_INSTR_SLOT_ALU_SCL_MUL) || 496bf215546Sopenharmony_ci (src_slots[i] == PPIR_INSTR_SLOT_ALU_VEC_MUL)) { 497bf215546Sopenharmony_ci src_to_swap = j; 498bf215546Sopenharmony_ci break; 499bf215546Sopenharmony_ci } 500bf215546Sopenharmony_ci } 501bf215546Sopenharmony_ci if (src_to_swap > 0) 502bf215546Sopenharmony_ci break; 503bf215546Sopenharmony_ci } 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_ci if (src_to_swap < 0) 506bf215546Sopenharmony_ci return true; 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ci /* Swap arguments so that we can use a pipeline register later on */ 509bf215546Sopenharmony_ci ppir_src tmp = alu->src[0]; 510bf215546Sopenharmony_ci alu->src[0] = alu->src[src_to_swap]; 511bf215546Sopenharmony_ci alu->src[src_to_swap] = tmp; 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_ci return true; 514bf215546Sopenharmony_ci} 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_cistatic bool (*ppir_lower_funcs[ppir_op_num])(ppir_block *, ppir_node *) = { 517bf215546Sopenharmony_ci [ppir_op_abs] = ppir_lower_abs, 518bf215546Sopenharmony_ci [ppir_op_neg] = ppir_lower_neg, 519bf215546Sopenharmony_ci [ppir_op_const] = ppir_lower_const, 520bf215546Sopenharmony_ci [ppir_op_ddx] = ppir_lower_ddxy, 521bf215546Sopenharmony_ci [ppir_op_ddy] = ppir_lower_ddxy, 522bf215546Sopenharmony_ci [ppir_op_lt] = ppir_lower_swap_args, 523bf215546Sopenharmony_ci [ppir_op_le] = ppir_lower_swap_args, 524bf215546Sopenharmony_ci [ppir_op_load_texture] = ppir_lower_texture, 525bf215546Sopenharmony_ci [ppir_op_select] = ppir_lower_select, 526bf215546Sopenharmony_ci [ppir_op_trunc] = ppir_lower_trunc, 527bf215546Sopenharmony_ci [ppir_op_sat] = ppir_lower_sat, 528bf215546Sopenharmony_ci [ppir_op_branch] = ppir_lower_branch, 529bf215546Sopenharmony_ci [ppir_op_load_uniform] = ppir_lower_load, 530bf215546Sopenharmony_ci [ppir_op_load_temp] = ppir_lower_load, 531bf215546Sopenharmony_ci [ppir_op_add] = ppir_lower_accum, 532bf215546Sopenharmony_ci [ppir_op_max] = ppir_lower_accum, 533bf215546Sopenharmony_ci [ppir_op_min] = ppir_lower_accum, 534bf215546Sopenharmony_ci [ppir_op_eq] = ppir_lower_accum, 535bf215546Sopenharmony_ci [ppir_op_ne] = ppir_lower_accum, 536bf215546Sopenharmony_ci}; 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_cibool ppir_lower_prog(ppir_compiler *comp) 539bf215546Sopenharmony_ci{ 540bf215546Sopenharmony_ci list_for_each_entry(ppir_block, block, &comp->block_list, list) { 541bf215546Sopenharmony_ci list_for_each_entry_safe(ppir_node, node, &block->node_list, list) { 542bf215546Sopenharmony_ci if (ppir_lower_funcs[node->op] && 543bf215546Sopenharmony_ci !ppir_lower_funcs[node->op](block, node)) 544bf215546Sopenharmony_ci return false; 545bf215546Sopenharmony_ci } 546bf215546Sopenharmony_ci } 547bf215546Sopenharmony_ci 548bf215546Sopenharmony_ci return true; 549bf215546Sopenharmony_ci} 550