• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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() == spv::Op::OpExtInst &&
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() == spv::Op::OpDecorate &&
50         spv::Decoration(r_inst->GetSingleWordInOperand(1)) ==
51             spv::Decoration::RelaxedPrecision)
52       return true;
53   return false;
54 }
55 
ProcessInst(Instruction * r_inst)56 bool RelaxFloatOpsPass::ProcessInst(Instruction* r_inst) {
57   uint32_t r_id = r_inst->result_id();
58   if (r_id == 0) return false;
59   if (!IsFloat32(r_inst)) return false;
60   if (IsRelaxed(r_id)) return false;
61   if (!IsRelaxable(r_inst)) return false;
62   get_decoration_mgr()->AddDecoration(
63       r_id, uint32_t(spv::Decoration::RelaxedPrecision));
64   return true;
65 }
66 
ProcessFunction(Function * func)67 bool RelaxFloatOpsPass::ProcessFunction(Function* func) {
68   bool modified = false;
69   cfg()->ForEachBlockInReversePostOrder(
70       func->entry().get(), [&modified, this](BasicBlock* bb) {
71         for (auto ii = bb->begin(); ii != bb->end(); ++ii)
72           modified |= ProcessInst(&*ii);
73       });
74   return modified;
75 }
76 
ProcessImpl()77 Pass::Status RelaxFloatOpsPass::ProcessImpl() {
78   Pass::ProcessFunction pfn = [this](Function* fp) {
79     return ProcessFunction(fp);
80   };
81   bool modified = context()->ProcessReachableCallTree(pfn);
82   return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
83 }
84 
Process()85 Pass::Status RelaxFloatOpsPass::Process() {
86   Initialize();
87   return ProcessImpl();
88 }
89 
Initialize()90 void RelaxFloatOpsPass::Initialize() {
91   target_ops_core_f_rslt_ = {
92       spv::Op::OpLoad,
93       spv::Op::OpPhi,
94       spv::Op::OpVectorExtractDynamic,
95       spv::Op::OpVectorInsertDynamic,
96       spv::Op::OpVectorShuffle,
97       spv::Op::OpCompositeExtract,
98       spv::Op::OpCompositeConstruct,
99       spv::Op::OpCompositeInsert,
100       spv::Op::OpCopyObject,
101       spv::Op::OpTranspose,
102       spv::Op::OpConvertSToF,
103       spv::Op::OpConvertUToF,
104       spv::Op::OpFConvert,
105       // spv::Op::OpQuantizeToF16,
106       spv::Op::OpFNegate,
107       spv::Op::OpFAdd,
108       spv::Op::OpFSub,
109       spv::Op::OpFMul,
110       spv::Op::OpFDiv,
111       spv::Op::OpFMod,
112       spv::Op::OpVectorTimesScalar,
113       spv::Op::OpMatrixTimesScalar,
114       spv::Op::OpVectorTimesMatrix,
115       spv::Op::OpMatrixTimesVector,
116       spv::Op::OpMatrixTimesMatrix,
117       spv::Op::OpOuterProduct,
118       spv::Op::OpDot,
119       spv::Op::OpSelect,
120   };
121   target_ops_core_f_opnd_ = {
122       spv::Op::OpFOrdEqual,
123       spv::Op::OpFUnordEqual,
124       spv::Op::OpFOrdNotEqual,
125       spv::Op::OpFUnordNotEqual,
126       spv::Op::OpFOrdLessThan,
127       spv::Op::OpFUnordLessThan,
128       spv::Op::OpFOrdGreaterThan,
129       spv::Op::OpFUnordGreaterThan,
130       spv::Op::OpFOrdLessThanEqual,
131       spv::Op::OpFUnordLessThanEqual,
132       spv::Op::OpFOrdGreaterThanEqual,
133       spv::Op::OpFUnordGreaterThanEqual,
134   };
135   target_ops_450_ = {
136       GLSLstd450Round, GLSLstd450RoundEven, GLSLstd450Trunc, GLSLstd450FAbs,
137       GLSLstd450FSign, GLSLstd450Floor, GLSLstd450Ceil, GLSLstd450Fract,
138       GLSLstd450Radians, GLSLstd450Degrees, GLSLstd450Sin, GLSLstd450Cos,
139       GLSLstd450Tan, GLSLstd450Asin, GLSLstd450Acos, GLSLstd450Atan,
140       GLSLstd450Sinh, GLSLstd450Cosh, GLSLstd450Tanh, GLSLstd450Asinh,
141       GLSLstd450Acosh, GLSLstd450Atanh, GLSLstd450Atan2, GLSLstd450Pow,
142       GLSLstd450Exp, GLSLstd450Log, GLSLstd450Exp2, GLSLstd450Log2,
143       GLSLstd450Sqrt, GLSLstd450InverseSqrt, GLSLstd450Determinant,
144       GLSLstd450MatrixInverse,
145       // TODO(greg-lunarg): GLSLstd450ModfStruct,
146       GLSLstd450FMin, GLSLstd450FMax, GLSLstd450FClamp, GLSLstd450FMix,
147       GLSLstd450Step, GLSLstd450SmoothStep, GLSLstd450Fma,
148       // TODO(greg-lunarg): GLSLstd450FrexpStruct,
149       GLSLstd450Ldexp, GLSLstd450Length, GLSLstd450Distance, GLSLstd450Cross,
150       GLSLstd450Normalize, GLSLstd450FaceForward, GLSLstd450Reflect,
151       GLSLstd450Refract, GLSLstd450NMin, GLSLstd450NMax, GLSLstd450NClamp};
152   sample_ops_ = {spv::Op::OpImageSampleImplicitLod,
153                  spv::Op::OpImageSampleExplicitLod,
154                  spv::Op::OpImageSampleDrefImplicitLod,
155                  spv::Op::OpImageSampleDrefExplicitLod,
156                  spv::Op::OpImageSampleProjImplicitLod,
157                  spv::Op::OpImageSampleProjExplicitLod,
158                  spv::Op::OpImageSampleProjDrefImplicitLod,
159                  spv::Op::OpImageSampleProjDrefExplicitLod,
160                  spv::Op::OpImageFetch,
161                  spv::Op::OpImageGather,
162                  spv::Op::OpImageDrefGather,
163                  spv::Op::OpImageRead,
164                  spv::Op::OpImageSparseSampleImplicitLod,
165                  spv::Op::OpImageSparseSampleExplicitLod,
166                  spv::Op::OpImageSparseSampleDrefImplicitLod,
167                  spv::Op::OpImageSparseSampleDrefExplicitLod,
168                  spv::Op::OpImageSparseSampleProjImplicitLod,
169                  spv::Op::OpImageSparseSampleProjExplicitLod,
170                  spv::Op::OpImageSparseSampleProjDrefImplicitLod,
171                  spv::Op::OpImageSparseSampleProjDrefExplicitLod,
172                  spv::Op::OpImageSparseFetch,
173                  spv::Op::OpImageSparseGather,
174                  spv::Op::OpImageSparseDrefGather,
175                  spv::Op::OpImageSparseTexelsResident,
176                  spv::Op::OpImageSparseRead};
177 }
178 
179 }  // namespace opt
180 }  // namespace spvtools
181