• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 Valve Corporation
2 // Copyright (c) 2019 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #ifndef LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_
17 #define LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_
18 
19 #include "source/opt/ir_builder.h"
20 #include "source/opt/pass.h"
21 
22 namespace spvtools {
23 namespace opt {
24 
25 class ConvertToHalfPass : public Pass {
26  public:
ConvertToHalfPass()27   ConvertToHalfPass() : Pass() {}
28 
29   ~ConvertToHalfPass() override = default;
30 
GetPreservedAnalyses()31   IRContext::Analysis GetPreservedAnalyses() override {
32     return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping;
33   }
34 
35   // See optimizer.hpp for pass user documentation.
36   Status Process() override;
37 
name()38   const char* name() const override { return "convert-to-half-pass"; }
39 
40  private:
41   // Return true if |inst| is an arithmetic, composite or phi op that can be
42   // of type float16
43   bool IsArithmetic(Instruction* inst);
44 
45   // Return true if |inst| returns scalar, vector or matrix type with base
46   // float and |width|
47   bool IsFloat(Instruction* inst, uint32_t width);
48   bool IsStruct(Instruction* inst);
49 
50   // Return true if |inst| is decorated with RelaxedPrecision
51   bool IsDecoratedRelaxed(Instruction* inst);
52 
53   // Return true if |id| has been added to the relaxed id set
54   bool IsRelaxed(uint32_t id);
55 
56   // Add |id| to the relaxed id set
57   void AddRelaxed(uint32_t id);
58 
59   // Return true if the instruction's operands can be relaxed
60   bool CanRelaxOpOperands(Instruction* inst);
61 
62   // Return type id for float with |width|
63   analysis::Type* FloatScalarType(uint32_t width);
64 
65   // Return type id for vector of length |vlen| of float of |width|
66   analysis::Type* FloatVectorType(uint32_t v_len, uint32_t width);
67 
68   // Return type id for matrix of |v_cnt| vectors of length identical to
69   // |vty_id| of float of |width|
70   analysis::Type* FloatMatrixType(uint32_t v_cnt, uint32_t vty_id,
71                                   uint32_t width);
72 
73   // Return equivalent to float type |ty_id| with |width|
74   uint32_t EquivFloatTypeId(uint32_t ty_id, uint32_t width);
75 
76   // Append instructions to builder to convert value |*val_idp| to type
77   // |ty_id| but with |width|. Set |*val_idp| to the new id.
78   void GenConvert(uint32_t* val_idp, uint32_t width, Instruction* inst);
79 
80   // Remove RelaxedPrecision decoration of |id|.
81   bool RemoveRelaxedDecoration(uint32_t id);
82 
83   // Add |inst| to relaxed instruction set if warranted. Specifically, if
84   // it is float32 and either decorated relaxed or a composite or phi
85   // instruction where all operands are relaxed or all uses are relaxed.
86   bool CloseRelaxInst(Instruction* inst);
87 
88   // If |inst| is an arithmetic, phi, extract or convert instruction of float32
89   // base type and decorated with RelaxedPrecision, change it to the equivalent
90   // float16 based type instruction. Specifically, insert instructions to
91   // convert all operands to float16 (if needed) and change its type to the
92   // equivalent float16 type. Otherwise, insert instructions to convert its
93   // operands back to their original types, if needed.
94   bool GenHalfInst(Instruction* inst);
95 
96   // Gen code for relaxed arithmetic |inst|
97   bool GenHalfArith(Instruction* inst);
98 
99   // Gen code for relaxed phi |inst|
100   bool ProcessPhi(Instruction* inst, uint32_t from_width, uint32_t to_width);
101 
102   // Gen code for relaxed convert |inst|
103   bool ProcessConvert(Instruction* inst);
104 
105   // Gen code for image reference |inst|
106   bool ProcessImageRef(Instruction* inst);
107 
108   // Process default non-relaxed |inst|
109   bool ProcessDefault(Instruction* inst);
110 
111   // If |inst| is an FConvert of a matrix type, decompose it to a series
112   // of vector extracts, converts and inserts into an Undef. These are
113   // generated by GenHalfInst because they are easier to manipulate, but are
114   // invalid so we need to clean them up.
115   bool MatConvertCleanup(Instruction* inst);
116 
117   // Call GenHalfInst on every instruction in |func|.
118   // If code is generated for an instruction, replace the instruction
119   // with the new instructions that are generated.
120   bool ProcessFunction(Function* func);
121 
122   Pass::Status ProcessImpl();
123 
124   // Initialize state for converting to half
125   void Initialize();
126 
127   struct hasher {
operatorhasher128     size_t operator()(const spv::Op& op) const noexcept {
129       return std::hash<uint32_t>()(uint32_t(op));
130     }
131   };
132 
133   // Set of core operations to be processed
134   std::unordered_set<spv::Op, hasher> target_ops_core_;
135 
136   // Set of 450 extension operations to be processed
137   std::unordered_set<uint32_t> target_ops_450_;
138 
139   // Set of all sample operations, including dref and non-dref operations
140   std::unordered_set<spv::Op, hasher> image_ops_;
141 
142   // Set of only dref sample operations
143   std::unordered_set<spv::Op, hasher> dref_image_ops_;
144 
145   // Set of operations that can be marked as relaxed
146   std::unordered_set<spv::Op, hasher> closure_ops_;
147 
148   // Set of ids of all relaxed instructions
149   std::unordered_set<uint32_t> relaxed_ids_set_;
150 
151   // Ids of all converted instructions
152   std::unordered_set<uint32_t> converted_ids_;
153 };
154 
155 }  // namespace opt
156 }  // namespace spvtools
157 
158 #endif  // LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_
159