1 /*
2  * Copyright © 2017 Gert Wollny
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #ifndef MESA_GLSL_TO_TGSI_ARRAY_MERGE_H
25 #define MESA_GLSL_TO_TGSI_ARRAY_MERGE_H
26 
27 
28 #include "st_glsl_to_tgsi_private.h"
29 #include <iosfwd>
30 
31 /* Until mesa/st officialy requires c++11 */
32 #if __cplusplus < 201103L
33 #define nullptr 0
34 #endif
35 
36 /* Helper class to merge the live ranges of an arrays.
37  *
38  * For arrays the array length, live range, and component access needs to
39  * be kept, because when live ranges are merged or arrays are interleaved
40  * one can only merge or interleave an array into another with equal or more
41  * elements. For interleaving it is also required that the sum of used swizzles
42  * is at most four.
43  */
44 class array_live_range {
45 public:
46    array_live_range();
47    array_live_range(unsigned aid, unsigned alength);
48    array_live_range(unsigned aid, unsigned alength, int first_access,
49 		  int last_access, int mask);
50 
51    void set_live_range(int first_access, int last_access);
set_begin(int _begin)52    void set_begin(int _begin){first_access = _begin;}
set_end(int _end)53    void set_end(int _end){last_access = _end;}
54    void set_access_mask(int s);
55 
56    static void merge(array_live_range *a, array_live_range *b);
57    static void interleave(array_live_range *a, array_live_range *b);
58 
array_id()59    int array_id() const {return id;}
target_array_id()60    int target_array_id() const {return target_array ? target_array->id : 0;}
final_target()61    const array_live_range *final_target() const {return target_array ?
62 	       target_array->final_target() : this;}
array_length()63    unsigned array_length() const { return length;}
begin()64    int begin() const { return first_access;}
end()65    int end() const { return last_access;}
access_mask()66    int access_mask() const { return component_access_mask;}
used_components()67    int used_components() const {return used_component_count;}
68 
69    bool time_doesnt_overlap(const array_live_range& other) const;
70 
71    void print(std::ostream& os) const;
72 
is_mapped()73    bool is_mapped() const { return target_array != nullptr;}
74 
75    int8_t remap_one_swizzle(int8_t idx) const;
76 
77 private:
78    void init_swizzles();
79    void set_target(array_live_range  *target);
80    void merge_live_range_from(array_live_range *other);
81    void interleave_into(array_live_range *other);
82 
83    unsigned id;
84    unsigned length;
85    int first_access;
86    int last_access;
87    uint8_t component_access_mask;
88    uint8_t used_component_count;
89    array_live_range *target_array;
90    int8_t swizzle_map[4];
91 };
92 
93 inline
94 std::ostream& operator << (std::ostream& os, const array_live_range& lt) {
95    lt.print(os);
96    return os;
97 }
98 
99 namespace tgsi_array_merge {
100 
101 /* Helper class to apply array merge and interleav to the shader.
102  * The interface is exposed here to make unit tests possible.
103  */
104 class array_remapping {
105 public:
106 
107    /** Create an invalid mapping that is used as place-holder for
108     * arrays that are not mapped at all.
109     */
110    array_remapping();
111 
112    /* Predefined remapping, needed for testing */
113    array_remapping(int trgt_array_id, const int8_t swizzle[]);
114 
115    /* Initialiaze the mapping from an array_live_range that has been
116     * processed by the array merge and interleave algorithm.
117     */
118    void init_from(const array_live_range& range);
119 
120    /* (Re)-set target id, needed when the mapping is resolved */
set_target_id(int tid)121    void set_target_id(int tid) {target_id = tid;}
122 
123    /* Defines a valid remapping */
is_valid()124    bool is_valid() const {return target_id > 0;}
125 
126    /* Translates the write mask to the new, interleaved component
127     * position
128     */
129    int map_writemask(int original_write_mask) const;
130 
131    /* Translates all read swizzles to the new, interleaved component
132     * swizzles
133     */
134    uint16_t map_swizzles(uint16_t original_swizzle) const;
135 
136    /* Move the read swizzles to the positiones that correspond to
137     * a changed write mask.
138     */
139    uint16_t move_read_swizzles(uint16_t original_swizzle) const;
140 
target_array_id()141    unsigned target_array_id() const {return target_id;}
142 
143    void print(std::ostream& os) const;
144 
145    friend bool operator == (const array_remapping& lhs,
146 			    const array_remapping& rhs);
147 
148 private:
149 
150    void interleave(int trgt_access_mask, int src_access_mask);
151 
152    unsigned target_id;
153    int8_t read_swizzle_map[4];
154 };
155 
156 inline
157 std::ostream& operator << (std::ostream& os, const array_remapping& am)
158 {
159    am.print(os);
160    return os;
161 }
162 
163 /* Apply the array remapping (internal use, exposed here for testing) */
164  bool get_array_remapping(int narrays, array_live_range *array_live_ranges,
165 			 array_remapping *remapping);
166 
167 /* Apply the array remapping (internal use, exposed here for testing) */
168 int remap_arrays(int narrays, unsigned *array_sizes,
169 		 exec_list *instructions,
170 		 array_remapping *map);
171 
172 }
173 
174 /** Remap the array access to finalize the array merging and interleaving.
175   * @param[in] narrays number of input arrays,
176   * @param[in,out] array_sizes length array of input arrays, on output the
177   *   array sizes will be updated according to the remapping,
178   * @param[in,out] instructions TGSI program, on output the arrays access is
179   *    remapped to the new array layout,
180   * @param[in] array_live_ranges live ranges and access information of the
181   *    arrays.
182   * @returns number of remaining arrays
183   */
184 int merge_arrays(int narrays,
185 		 unsigned *array_sizes,
186 		 exec_list *instructions,
187 		 class array_live_range *arr_live_ranges);
188 #endif
189