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