Coverage Report

Created: 2023-03-01 07:33

/src/spirv-tools/source/opt/convert_to_half_pass.h
Line
Count
Source (jump to first uncovered line)
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:
27
0
  ConvertToHalfPass() : Pass() {}
28
29
0
  ~ConvertToHalfPass() override = default;
30
31
0
  IRContext::Analysis GetPreservedAnalyses() override {
32
0
    return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping;
33
0
  }
34
35
  // See optimizer.hpp for pass user documentation.
36
  Status Process() override;
37
38
0
  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
49
  // Return true if |inst| is decorated with RelaxedPrecision
50
  bool IsDecoratedRelaxed(Instruction* inst);
51
52
  // Return true if |id| has been added to the relaxed id set
53
  bool IsRelaxed(uint32_t id);
54
55
  // Add |id| to the relaxed id set
56
  void AddRelaxed(uint32_t id);
57
58
  // Return type id for float with |width|
59
  analysis::Type* FloatScalarType(uint32_t width);
60
61
  // Return type id for vector of length |vlen| of float of |width|
62
  analysis::Type* FloatVectorType(uint32_t v_len, uint32_t width);
63
64
  // Return type id for matrix of |v_cnt| vectors of length identical to
65
  // |vty_id| of float of |width|
66
  analysis::Type* FloatMatrixType(uint32_t v_cnt, uint32_t vty_id,
67
                                  uint32_t width);
68
69
  // Return equivalent to float type |ty_id| with |width|
70
  uint32_t EquivFloatTypeId(uint32_t ty_id, uint32_t width);
71
72
  // Append instructions to builder to convert value |*val_idp| to type
73
  // |ty_id| but with |width|. Set |*val_idp| to the new id.
74
  void GenConvert(uint32_t* val_idp, uint32_t width, Instruction* inst);
75
76
  // Remove RelaxedPrecision decoration of |id|.
77
  bool RemoveRelaxedDecoration(uint32_t id);
78
79
  // Add |inst| to relaxed instruction set if warranted. Specifically, if
80
  // it is float32 and either decorated relaxed or a composite or phi
81
  // instruction where all operands are relaxed or all uses are relaxed.
82
  bool CloseRelaxInst(Instruction* inst);
83
84
  // If |inst| is an arithmetic, phi, extract or convert instruction of float32
85
  // base type and decorated with RelaxedPrecision, change it to the equivalent
86
  // float16 based type instruction. Specifically, insert instructions to
87
  // convert all operands to float16 (if needed) and change its type to the
88
  // equivalent float16 type. Otherwise, insert instructions to convert its
89
  // operands back to their original types, if needed.
90
  bool GenHalfInst(Instruction* inst);
91
92
  // Gen code for relaxed arithmetic |inst|
93
  bool GenHalfArith(Instruction* inst);
94
95
  // Gen code for relaxed phi |inst|
96
  bool ProcessPhi(Instruction* inst, uint32_t from_width, uint32_t to_width);
97
98
  // Gen code for relaxed convert |inst|
99
  bool ProcessConvert(Instruction* inst);
100
101
  // Gen code for image reference |inst|
102
  bool ProcessImageRef(Instruction* inst);
103
104
  // Process default non-relaxed |inst|
105
  bool ProcessDefault(Instruction* inst);
106
107
  // If |inst| is an FConvert of a matrix type, decompose it to a series
108
  // of vector extracts, converts and inserts into an Undef. These are
109
  // generated by GenHalfInst because they are easier to manipulate, but are
110
  // invalid so we need to clean them up.
111
  bool MatConvertCleanup(Instruction* inst);
112
113
  // Call GenHalfInst on every instruction in |func|.
114
  // If code is generated for an instruction, replace the instruction
115
  // with the new instructions that are generated.
116
  bool ProcessFunction(Function* func);
117
118
  Pass::Status ProcessImpl();
119
120
  // Initialize state for converting to half
121
  void Initialize();
122
123
  struct hasher {
124
0
    size_t operator()(const spv::Op& op) const noexcept {
125
0
      return std::hash<uint32_t>()(uint32_t(op));
126
0
    }
127
  };
128
129
  // Set of core operations to be processed
130
  std::unordered_set<spv::Op, hasher> target_ops_core_;
131
132
  // Set of 450 extension operations to be processed
133
  std::unordered_set<uint32_t> target_ops_450_;
134
135
  // Set of sample operations
136
  std::unordered_set<spv::Op, hasher> image_ops_;
137
138
  // Set of dref sample operations
139
  std::unordered_set<spv::Op, hasher> dref_image_ops_;
140
141
  // Set of dref sample operations
142
  std::unordered_set<spv::Op, hasher> closure_ops_;
143
144
  // Set of ids of all relaxed instructions
145
  std::unordered_set<uint32_t> relaxed_ids_set_;
146
147
  // Ids of all converted instructions
148
  std::unordered_set<uint32_t> converted_ids_;
149
};
150
151
}  // namespace opt
152
}  // namespace spvtools
153
154
#endif  // LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_