1 | // Copyright (c) 2019 The Khronos Group Inc. |
2 | // Copyright (c) 2019 Valve Corporation |
3 | // Copyright (c) 2019 LunarG Inc. |
4 | // |
5 | // Licensed under the Apache License, Version 2.0 (the "License"); |
6 | // you may not use this file except in compliance with the License. |
7 | // You may obtain a copy of the License at |
8 | // |
9 | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | // |
11 | // Unless required by applicable law or agreed to in writing, software |
12 | // distributed under the License is distributed on an "AS IS" BASIS, |
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | // See the License for the specific language governing permissions and |
15 | // limitations under the License. |
16 | |
17 | #include "relax_float_ops_pass.h" |
18 | |
19 | #include "source/opt/ir_builder.h" |
20 | |
21 | namespace spvtools { |
22 | namespace opt { |
23 | |
24 | bool RelaxFloatOpsPass::IsRelaxable(Instruction* inst) { |
25 | return target_ops_core_f_rslt_.count(inst->opcode()) != 0 || |
26 | target_ops_core_f_opnd_.count(inst->opcode()) != 0 || |
27 | sample_ops_.count(inst->opcode()) != 0 || |
28 | (inst->opcode() == SpvOpExtInst && |
29 | inst->GetSingleWordInOperand(0) == |
30 | context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450() && |
31 | target_ops_450_.count(inst->GetSingleWordInOperand(1)) != 0); |
32 | } |
33 | |
34 | bool RelaxFloatOpsPass::IsFloat32(Instruction* inst) { |
35 | uint32_t ty_id; |
36 | if (target_ops_core_f_opnd_.count(inst->opcode()) != 0) { |
37 | uint32_t opnd_id = inst->GetSingleWordInOperand(0); |
38 | Instruction* opnd_inst = get_def_use_mgr()->GetDef(opnd_id); |
39 | ty_id = opnd_inst->type_id(); |
40 | } else { |
41 | ty_id = inst->type_id(); |
42 | if (ty_id == 0) return false; |
43 | } |
44 | return IsFloat(ty_id, 32); |
45 | } |
46 | |
47 | bool RelaxFloatOpsPass::IsRelaxed(uint32_t r_id) { |
48 | for (auto r_inst : get_decoration_mgr()->GetDecorationsFor(r_id, false)) |
49 | if (r_inst->opcode() == SpvOpDecorate && |
50 | r_inst->GetSingleWordInOperand(1) == SpvDecorationRelaxedPrecision) |
51 | return true; |
52 | return false; |
53 | } |
54 | |
55 | bool RelaxFloatOpsPass::ProcessInst(Instruction* r_inst) { |
56 | uint32_t r_id = r_inst->result_id(); |
57 | if (r_id == 0) return false; |
58 | if (!IsFloat32(r_inst)) return false; |
59 | if (IsRelaxed(r_id)) return false; |
60 | if (!IsRelaxable(r_inst)) return false; |
61 | get_decoration_mgr()->AddDecoration(r_id, SpvDecorationRelaxedPrecision); |
62 | return true; |
63 | } |
64 | |
65 | bool RelaxFloatOpsPass::ProcessFunction(Function* func) { |
66 | bool modified = false; |
67 | cfg()->ForEachBlockInReversePostOrder( |
68 | func->entry().get(), [&modified, this](BasicBlock* bb) { |
69 | for (auto ii = bb->begin(); ii != bb->end(); ++ii) |
70 | modified |= ProcessInst(&*ii); |
71 | }); |
72 | return modified; |
73 | } |
74 | |
75 | Pass::Status RelaxFloatOpsPass::ProcessImpl() { |
76 | Pass::ProcessFunction pfn = [this](Function* fp) { |
77 | return ProcessFunction(fp); |
78 | }; |
79 | bool modified = context()->ProcessEntryPointCallTree(pfn); |
80 | return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; |
81 | } |
82 | |
83 | Pass::Status RelaxFloatOpsPass::Process() { |
84 | Initialize(); |
85 | return ProcessImpl(); |
86 | } |
87 | |
88 | void RelaxFloatOpsPass::Initialize() { |
89 | target_ops_core_f_rslt_ = { |
90 | SpvOpLoad, |
91 | SpvOpPhi, |
92 | SpvOpVectorExtractDynamic, |
93 | SpvOpVectorInsertDynamic, |
94 | SpvOpVectorShuffle, |
95 | SpvOpCompositeExtract, |
96 | SpvOpCompositeConstruct, |
97 | SpvOpCompositeInsert, |
98 | SpvOpCopyObject, |
99 | SpvOpTranspose, |
100 | SpvOpConvertSToF, |
101 | SpvOpConvertUToF, |
102 | SpvOpFConvert, |
103 | // SpvOpQuantizeToF16, |
104 | SpvOpFNegate, |
105 | SpvOpFAdd, |
106 | SpvOpFSub, |
107 | SpvOpFMul, |
108 | SpvOpFDiv, |
109 | SpvOpFMod, |
110 | SpvOpVectorTimesScalar, |
111 | SpvOpMatrixTimesScalar, |
112 | SpvOpVectorTimesMatrix, |
113 | SpvOpMatrixTimesVector, |
114 | SpvOpMatrixTimesMatrix, |
115 | SpvOpOuterProduct, |
116 | SpvOpDot, |
117 | SpvOpSelect, |
118 | }; |
119 | target_ops_core_f_opnd_ = { |
120 | SpvOpFOrdEqual, |
121 | SpvOpFUnordEqual, |
122 | SpvOpFOrdNotEqual, |
123 | SpvOpFUnordNotEqual, |
124 | SpvOpFOrdLessThan, |
125 | SpvOpFUnordLessThan, |
126 | SpvOpFOrdGreaterThan, |
127 | SpvOpFUnordGreaterThan, |
128 | SpvOpFOrdLessThanEqual, |
129 | SpvOpFUnordLessThanEqual, |
130 | SpvOpFOrdGreaterThanEqual, |
131 | SpvOpFUnordGreaterThanEqual, |
132 | }; |
133 | target_ops_450_ = { |
134 | GLSLstd450Round, GLSLstd450RoundEven, GLSLstd450Trunc, GLSLstd450FAbs, |
135 | GLSLstd450FSign, GLSLstd450Floor, GLSLstd450Ceil, GLSLstd450Fract, |
136 | GLSLstd450Radians, GLSLstd450Degrees, GLSLstd450Sin, GLSLstd450Cos, |
137 | GLSLstd450Tan, GLSLstd450Asin, GLSLstd450Acos, GLSLstd450Atan, |
138 | GLSLstd450Sinh, GLSLstd450Cosh, GLSLstd450Tanh, GLSLstd450Asinh, |
139 | GLSLstd450Acosh, GLSLstd450Atanh, GLSLstd450Atan2, GLSLstd450Pow, |
140 | GLSLstd450Exp, GLSLstd450Log, GLSLstd450Exp2, GLSLstd450Log2, |
141 | GLSLstd450Sqrt, GLSLstd450InverseSqrt, GLSLstd450Determinant, |
142 | GLSLstd450MatrixInverse, |
143 | // TODO(greg-lunarg): GLSLstd450ModfStruct, |
144 | GLSLstd450FMin, GLSLstd450FMax, GLSLstd450FClamp, GLSLstd450FMix, |
145 | GLSLstd450Step, GLSLstd450SmoothStep, GLSLstd450Fma, |
146 | // TODO(greg-lunarg): GLSLstd450FrexpStruct, |
147 | GLSLstd450Ldexp, GLSLstd450Length, GLSLstd450Distance, GLSLstd450Cross, |
148 | GLSLstd450Normalize, GLSLstd450FaceForward, GLSLstd450Reflect, |
149 | GLSLstd450Refract, GLSLstd450NMin, GLSLstd450NMax, GLSLstd450NClamp}; |
150 | sample_ops_ = {SpvOpImageSampleImplicitLod, |
151 | SpvOpImageSampleExplicitLod, |
152 | SpvOpImageSampleDrefImplicitLod, |
153 | SpvOpImageSampleDrefExplicitLod, |
154 | SpvOpImageSampleProjImplicitLod, |
155 | SpvOpImageSampleProjExplicitLod, |
156 | SpvOpImageSampleProjDrefImplicitLod, |
157 | SpvOpImageSampleProjDrefExplicitLod, |
158 | SpvOpImageFetch, |
159 | SpvOpImageGather, |
160 | SpvOpImageDrefGather, |
161 | SpvOpImageRead, |
162 | SpvOpImageSparseSampleImplicitLod, |
163 | SpvOpImageSparseSampleExplicitLod, |
164 | SpvOpImageSparseSampleDrefImplicitLod, |
165 | SpvOpImageSparseSampleDrefExplicitLod, |
166 | SpvOpImageSparseSampleProjImplicitLod, |
167 | SpvOpImageSparseSampleProjExplicitLod, |
168 | SpvOpImageSparseSampleProjDrefImplicitLod, |
169 | SpvOpImageSparseSampleProjDrefExplicitLod, |
170 | SpvOpImageSparseFetch, |
171 | SpvOpImageSparseGather, |
172 | SpvOpImageSparseDrefGather, |
173 | SpvOpImageSparseTexelsResident, |
174 | SpvOpImageSparseRead}; |
175 | } |
176 | |
177 | } // namespace opt |
178 | } // namespace spvtools |
179 | |