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
21namespace spvtools {
22namespace opt {
23
24bool 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
34bool 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
47bool 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
55bool 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
65bool 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
75Pass::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
83Pass::Status RelaxFloatOpsPass::Process() {
84 Initialize();
85 return ProcessImpl();
86}
87
88void 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