SPIRV-Tools/source/opt/convert_to_half_pass.h
greg-lunarg d11725b1d4 Add --relax-float-ops and --convert-relaxed-to-half (#2808)
The first pass applies the RelaxedPrecision decoration to all executable
instructions with float32 based type results. The second pass converts
all executable instructions with RelaxedPrecision result to the equivalent
float16 type, inserting converts where necessary.
2019-09-03 13:22:13 -04:00

135 lines
4.6 KiB
C++

// Copyright (c) 2019 Valve Corporation
// Copyright (c) 2019 LunarG Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_
#define LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_
#include "source/opt/ir_builder.h"
#include "source/opt/pass.h"
namespace spvtools {
namespace opt {
class ConvertToHalfPass : public Pass {
public:
ConvertToHalfPass() : Pass() {}
~ConvertToHalfPass() override = default;
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping;
}
// See optimizer.hpp for pass user documentation.
Status Process() override;
const char* name() const override { return "convert-to-half-pass"; }
private:
// Return true if |inst| is an arithmetic op that can be of type float16
bool IsArithmetic(Instruction* inst);
// Return true if |inst| returns scalar, vector or matrix type with base
// float and |width|
bool IsFloat(Instruction* inst, uint32_t width);
// Return true if |inst| is decorated with RelaxedPrecision
bool IsRelaxed(Instruction* inst);
// Return type id for float with |width|
analysis::Type* FloatScalarType(uint32_t width);
// Return type id for vector of length |vlen| of float of |width|
analysis::Type* FloatVectorType(uint32_t v_len, uint32_t width);
// Return type id for matrix of |v_cnt| vectors of length identical to
// |vty_id| of float of |width|
analysis::Type* FloatMatrixType(uint32_t v_cnt, uint32_t vty_id,
uint32_t width);
// Return equivalent to float type |ty_id| with |width|
uint32_t EquivFloatTypeId(uint32_t ty_id, uint32_t width);
// Append instructions to builder to convert value |*val_idp| to type
// |ty_id| but with |width|. Set |*val_idp| to the new id.
void GenConvert(uint32_t* val_idp, uint32_t width,
InstructionBuilder* builder);
// Remove RelaxedPrecision decoration of |id|.
void RemoveRelaxedDecoration(uint32_t id);
// If |inst| is an arithmetic, phi, extract or convert instruction of float32
// base type and decorated with RelaxedPrecision, change it to the equivalent
// float16 based type instruction. Specifically, insert instructions to
// convert all operands to float16 (if needed) and change its type to the
// equivalent float16 type. Otherwise, insert instructions to convert its
// operands back to their original types, if needed.
bool GenHalfCode(Instruction* inst);
// Gen code for relaxed arithmetic |inst|
bool GenHalfArith(Instruction* inst);
// Gen code for relaxed phi |inst|
bool ProcessPhi(Instruction* inst);
// Gen code for relaxed extract |inst|
bool ProcessExtract(Instruction* inst);
// Gen code for relaxed convert |inst|
bool ProcessConvert(Instruction* inst);
// Gen code for image reference |inst|
bool ProcessImageRef(Instruction* inst);
// Process default non-relaxed |inst|
bool ProcessDefault(Instruction* inst);
// If |inst| is an FConvert of a matrix type, decompose it to a series
// of vector extracts, converts and inserts into an Undef. These are
// generated by GenHalfCode because they are easier to manipulate, but are
// invalid so we need to clean them up.
bool MatConvertCleanup(Instruction* inst);
// Call GenHalfCode on every instruction in |func|.
// If code is generated for an instruction, replace the instruction
// with the new instructions that are generated.
bool ProcessFunction(Function* func);
Pass::Status ProcessImpl();
// Initialize state for converting to half
void Initialize();
// Set of core operations to be processed
std::unordered_set<uint32_t> target_ops_core_;
// Set of 450 extension operations to be processed
std::unordered_set<uint32_t> target_ops_450_;
// Set of sample operations
std::unordered_set<uint32_t> image_ops_;
// Set of dref sample operations
std::unordered_set<uint32_t> dref_image_ops_;
// Ids of all converted instructions
std::vector<uint32_t> relaxed_ids_;
};
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_