1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2014 Valve Corporation
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 FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "ir3.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#define XXH_INLINE_ALL
27bf215546Sopenharmony_ci#include "xxhash.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci/* This pass handles CSE'ing repeated expressions created in the process of
30bf215546Sopenharmony_ci * translating from NIR. Currently this is just collect's. Also, currently
31bf215546Sopenharmony_ci * this is intra-block only, to make it work over multiple block we'd need to
32bf215546Sopenharmony_ci * bring forward dominance calculation.
33bf215546Sopenharmony_ci */
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#define HASH(hash, data) XXH32(&(data), sizeof(data), hash)
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_cistatic uint32_t
38bf215546Sopenharmony_cihash_instr(const void *data)
39bf215546Sopenharmony_ci{
40bf215546Sopenharmony_ci   const struct ir3_instruction *instr = data;
41bf215546Sopenharmony_ci   uint32_t hash = 0;
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci   hash = HASH(hash, instr->opc);
44bf215546Sopenharmony_ci   hash = HASH(hash, instr->dsts[0]->flags);
45bf215546Sopenharmony_ci   foreach_src (src, (struct ir3_instruction *)instr) {
46bf215546Sopenharmony_ci      if (src->flags & IR3_REG_CONST) {
47bf215546Sopenharmony_ci         if (src->flags & IR3_REG_RELATIV)
48bf215546Sopenharmony_ci            hash = HASH(hash, src->array.offset);
49bf215546Sopenharmony_ci         else
50bf215546Sopenharmony_ci            hash = HASH(hash, src->num);
51bf215546Sopenharmony_ci      } else if (src->flags & IR3_REG_IMMED) {
52bf215546Sopenharmony_ci         hash = HASH(hash, src->uim_val);
53bf215546Sopenharmony_ci      } else {
54bf215546Sopenharmony_ci         if (src->flags & IR3_REG_ARRAY)
55bf215546Sopenharmony_ci            hash = HASH(hash, src->array.offset);
56bf215546Sopenharmony_ci         hash = HASH(hash, src->def);
57bf215546Sopenharmony_ci      }
58bf215546Sopenharmony_ci   }
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci   if (opc_cat(instr->opc) == 1) {
61bf215546Sopenharmony_ci      hash = HASH(hash, instr->cat1.dst_type);
62bf215546Sopenharmony_ci      hash = HASH(hash, instr->cat1.src_type);
63bf215546Sopenharmony_ci      hash = HASH(hash, instr->cat1.round);
64bf215546Sopenharmony_ci   }
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   return hash;
67bf215546Sopenharmony_ci}
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_cistatic bool
70bf215546Sopenharmony_ciinstrs_equal(const struct ir3_instruction *i1, const struct ir3_instruction *i2)
71bf215546Sopenharmony_ci{
72bf215546Sopenharmony_ci   if (i1->opc != i2->opc)
73bf215546Sopenharmony_ci      return false;
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci   if (i1->dsts_count != i2->dsts_count)
76bf215546Sopenharmony_ci      return false;
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   if (i1->srcs_count != i2->srcs_count)
79bf215546Sopenharmony_ci      return false;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   if (i1->dsts[0]->flags != i2->dsts[0]->flags)
82bf215546Sopenharmony_ci      return false;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   for (unsigned i = 0; i < i1->srcs_count; i++) {
85bf215546Sopenharmony_ci      const struct ir3_register *i1_reg = i1->srcs[i], *i2_reg = i2->srcs[i];
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci      if (i1_reg->flags != i2_reg->flags)
88bf215546Sopenharmony_ci         return false;
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci      if (i1_reg->flags & IR3_REG_CONST) {
91bf215546Sopenharmony_ci         if (i1_reg->flags & IR3_REG_RELATIV) {
92bf215546Sopenharmony_ci            if (i1_reg->array.offset != i2_reg->array.offset)
93bf215546Sopenharmony_ci               return false;
94bf215546Sopenharmony_ci         } else {
95bf215546Sopenharmony_ci            if (i1_reg->num != i2_reg->num)
96bf215546Sopenharmony_ci               return false;
97bf215546Sopenharmony_ci         }
98bf215546Sopenharmony_ci      } else if (i1_reg->flags & IR3_REG_IMMED) {
99bf215546Sopenharmony_ci         if (i1_reg->uim_val != i2_reg->uim_val)
100bf215546Sopenharmony_ci            return false;
101bf215546Sopenharmony_ci      } else {
102bf215546Sopenharmony_ci         if (i1_reg->flags & IR3_REG_ARRAY) {
103bf215546Sopenharmony_ci            if (i1_reg->array.offset != i2_reg->array.offset)
104bf215546Sopenharmony_ci               return false;
105bf215546Sopenharmony_ci         }
106bf215546Sopenharmony_ci         if (i1_reg->def != i2_reg->def)
107bf215546Sopenharmony_ci            return false;
108bf215546Sopenharmony_ci      }
109bf215546Sopenharmony_ci   }
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci   if (opc_cat(i1->opc) == 1) {
112bf215546Sopenharmony_ci      if (i1->cat1.dst_type != i2->cat1.dst_type ||
113bf215546Sopenharmony_ci          i1->cat1.src_type != i2->cat1.src_type ||
114bf215546Sopenharmony_ci          i1->cat1.round != i2->cat1.round)
115bf215546Sopenharmony_ci         return false;
116bf215546Sopenharmony_ci   }
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   return true;
119bf215546Sopenharmony_ci}
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_cistatic bool
122bf215546Sopenharmony_ciinstr_can_cse(const struct ir3_instruction *instr)
123bf215546Sopenharmony_ci{
124bf215546Sopenharmony_ci   if (instr->opc != OPC_META_COLLECT && instr->opc != OPC_MOV)
125bf215546Sopenharmony_ci      return false;
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   if (!is_dest_gpr(instr->dsts[0]) || (instr->dsts[0]->flags & IR3_REG_ARRAY))
128bf215546Sopenharmony_ci      return false;
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   return true;
131bf215546Sopenharmony_ci}
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_cistatic bool
134bf215546Sopenharmony_cicmp_func(const void *data1, const void *data2)
135bf215546Sopenharmony_ci{
136bf215546Sopenharmony_ci   return instrs_equal(data1, data2);
137bf215546Sopenharmony_ci}
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_cibool
140bf215546Sopenharmony_ciir3_cse(struct ir3 *ir)
141bf215546Sopenharmony_ci{
142bf215546Sopenharmony_ci   struct set *instr_set = _mesa_set_create(NULL, hash_instr, cmp_func);
143bf215546Sopenharmony_ci   foreach_block (block, &ir->block_list) {
144bf215546Sopenharmony_ci      _mesa_set_clear(instr_set, NULL);
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci      foreach_instr (instr, &block->instr_list) {
147bf215546Sopenharmony_ci         instr->data = NULL;
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci         if (!instr_can_cse(instr))
150bf215546Sopenharmony_ci            continue;
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci         bool found;
153bf215546Sopenharmony_ci         struct set_entry *entry =
154bf215546Sopenharmony_ci            _mesa_set_search_or_add(instr_set, instr, &found);
155bf215546Sopenharmony_ci         if (found)
156bf215546Sopenharmony_ci            instr->data = (void *)entry->key;
157bf215546Sopenharmony_ci      }
158bf215546Sopenharmony_ci   }
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   bool progress = false;
161bf215546Sopenharmony_ci   foreach_block (block, &ir->block_list) {
162bf215546Sopenharmony_ci      foreach_instr (instr, &block->instr_list) {
163bf215546Sopenharmony_ci         foreach_src (src, instr) {
164bf215546Sopenharmony_ci            if ((src->flags & IR3_REG_SSA) && src->def &&
165bf215546Sopenharmony_ci                src->def->instr->data) {
166bf215546Sopenharmony_ci               progress = true;
167bf215546Sopenharmony_ci               struct ir3_instruction *instr = src->def->instr->data;
168bf215546Sopenharmony_ci               src->def = instr->dsts[0];
169bf215546Sopenharmony_ci            }
170bf215546Sopenharmony_ci         }
171bf215546Sopenharmony_ci      }
172bf215546Sopenharmony_ci   }
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   _mesa_set_destroy(instr_set, NULL);
175bf215546Sopenharmony_ci   return progress;
176bf215546Sopenharmony_ci}
177