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 
IsRelaxable(Instruction * inst)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 
IsFloat32(Instruction * inst)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 
IsRelaxed(uint32_t r_id)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 
ProcessInst(Instruction * r_inst)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 
ProcessFunction(Function * func)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 
ProcessImpl()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 
Process()83 Pass::Status RelaxFloatOpsPass::Process() {
84   Initialize();
85   return ProcessImpl();
86 }
87 
Initialize()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