// Copyright (c) 2018 Google LLC // // 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. #include "source/opt/const_folding_rules.h" #include "source/opt/ir_context.h" namespace spvtools { namespace opt { namespace { constexpr uint32_t kExtractCompositeIdInIdx = …; // Returns a constants with the value NaN of the given type. Only works for // 32-bit and 64-bit float point types. Returns |nullptr| if an error occurs. const analysis::Constant* GetNan(const analysis::Type* type, analysis::ConstantManager* const_mgr) { … } // Returns a constants with the value INF of the given type. Only works for // 32-bit and 64-bit float point types. Returns |nullptr| if an error occurs. const analysis::Constant* GetInf(const analysis::Type* type, analysis::ConstantManager* const_mgr) { … } // Returns true if |type| is Float or a vector of Float. bool HasFloatingPoint(const analysis::Type* type) { … } // Returns a constants with the value |-val| of the given type. Only works for // 32-bit and 64-bit float point types. Returns |nullptr| if an error occurs. const analysis::Constant* NegateFPConst(const analysis::Type* result_type, const analysis::Constant* val, analysis::ConstantManager* const_mgr) { … } // Returns a constants with the value |-val| of the given type. const analysis::Constant* NegateIntConst(const analysis::Type* result_type, const analysis::Constant* val, analysis::ConstantManager* const_mgr) { … } // Folds an OpcompositeExtract where input is a composite constant. ConstantFoldingRule FoldExtractWithConstants() { … } // Folds an OpcompositeInsert where input is a composite constant. ConstantFoldingRule FoldInsertWithConstants() { … } ConstantFoldingRule FoldVectorShuffleWithConstants() { … } ConstantFoldingRule FoldVectorTimesScalar() { … } // Returns to the constant that results from tranposing |matrix|. The result // will have type |result_type|, and |matrix| must exist in |context|. The // result constant will also exist in |context|. const analysis::Constant* TransposeMatrix(const analysis::Constant* matrix, analysis::Matrix* result_type, IRContext* context) { … } const analysis::Constant* FoldTranspose( IRContext* context, Instruction* inst, const std::vector<const analysis::Constant*>& constants) { … } ConstantFoldingRule FoldVectorTimesMatrix() { … } ConstantFoldingRule FoldMatrixTimesVector() { … } ConstantFoldingRule FoldCompositeWithConstants() { … } // The interface for a function that returns the result of applying a scalar // floating-point binary operation on |a| and |b|. The type of the return value // will be |type|. The input constants must also be of type |type|. UnaryScalarFoldingRule; // The interface for a function that returns the result of applying a scalar // floating-point binary operation on |a| and |b|. The type of the return value // will be |type|. The input constants must also be of type |type|. BinaryScalarFoldingRule; // Returns a |ConstantFoldingRule| that folds unary scalar ops // using |scalar_rule| and unary vectors ops by applying // |scalar_rule| to the elements of the vector. The |ConstantFoldingRule| // that is returned assumes that |constants| contains 1 entry. If they are // not |nullptr|, then their type is either |Float| or |Integer| or a |Vector| // whose element type is |Float| or |Integer|. ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) { … } // Returns a |ConstantFoldingRule| that folds binary scalar ops // using |scalar_rule| and binary vectors ops by applying // |scalar_rule| to the elements of the vector. The folding rule assumes that op // has two inputs. For regular instruction, those are in operands 0 and 1. For // extended instruction, they are in operands 1 and 2. If an element in // |constants| is not nullprt, then the constant's type is |Float|, |Integer|, // or |Vector| whose element type is |Float| or |Integer|. ConstantFoldingRule FoldBinaryOp(BinaryScalarFoldingRule scalar_rule) { … } // Returns a |ConstantFoldingRule| that folds unary floating point scalar ops // using |scalar_rule| and unary float point vectors ops by applying // |scalar_rule| to the elements of the vector. The |ConstantFoldingRule| // that is returned assumes that |constants| contains 1 entry. If they are // not |nullptr|, then their type is either |Float| or |Integer| or a |Vector| // whose element type is |Float| or |Integer|. ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) { … } // Returns the result of folding the constants in |constants| according the // |scalar_rule|. If |result_type| is a vector, then |scalar_rule| is applied // per component. const analysis::Constant* FoldFPBinaryOp( BinaryScalarFoldingRule scalar_rule, uint32_t result_type_id, const std::vector<const analysis::Constant*>& constants, IRContext* context) { … } // Returns a |ConstantFoldingRule| that folds floating point scalars using // |scalar_rule| and vectors of floating point by applying |scalar_rule| to the // elements of the vector. The |ConstantFoldingRule| that is returned assumes // that |constants| contains 2 entries. If they are not |nullptr|, then their // type is either |Float| or a |Vector| whose element type is |Float|. ConstantFoldingRule FoldFPBinaryOp(BinaryScalarFoldingRule scalar_rule) { … } // This macro defines a |UnaryScalarFoldingRule| that performs float to // integer conversion. // TODO(greg-lunarg): Support for 64-bit integer types. UnaryScalarFoldingRule FoldFToIOp() { … } // This function defines a |UnaryScalarFoldingRule| that performs integer to // float conversion. // TODO(greg-lunarg): Support for 64-bit integer types. UnaryScalarFoldingRule FoldIToFOp() { … } // This defines a |UnaryScalarFoldingRule| that performs |OpQuantizeToF16|. UnaryScalarFoldingRule FoldQuantizeToF16Scalar() { … } // This macro defines a |BinaryScalarFoldingRule| that applies |op|. The // operator |op| must work for both float and double, and use syntax "f1 op f2". #define FOLD_FPARITH_OP(op) … // Define the folding rule for conversion between floating point and integer ConstantFoldingRule FoldFToI() { … } ConstantFoldingRule FoldIToF() { … } ConstantFoldingRule FoldQuantizeToF16() { … } // Define the folding rules for subtraction, addition, multiplication, and // division for floating point values. ConstantFoldingRule FoldFSub() { … } ConstantFoldingRule FoldFAdd() { … } ConstantFoldingRule FoldFMul() { … } // Returns the constant that results from evaluating |numerator| / 0.0. Returns // |nullptr| if the result could not be evaluated. const analysis::Constant* FoldFPScalarDivideByZero( const analysis::Type* result_type, const analysis::Constant* numerator, analysis::ConstantManager* const_mgr) { … } // Returns the result of folding |numerator| / |denominator|. Returns |nullptr| // if it cannot be folded. const analysis::Constant* FoldScalarFPDivide( const analysis::Type* result_type, const analysis::Constant* numerator, const analysis::Constant* denominator, analysis::ConstantManager* const_mgr) { … } // Returns the constant folding rule to fold |OpFDiv| with two constants. ConstantFoldingRule FoldFDiv() { … } bool CompareFloatingPoint(bool op_result, bool op_unordered, bool need_ordered) { … } // This macro defines a |BinaryScalarFoldingRule| that applies |op|. The // operator |op| must work for both float and double, and use syntax "f1 op f2". #define FOLD_FPCMP_OP(op, ord) … // Define the folding rules for ordered and unordered comparison for floating // point values. ConstantFoldingRule FoldFOrdEqual() { … } ConstantFoldingRule FoldFUnordEqual() { … } ConstantFoldingRule FoldFOrdNotEqual() { … } ConstantFoldingRule FoldFUnordNotEqual() { … } ConstantFoldingRule FoldFOrdLessThan() { … } ConstantFoldingRule FoldFUnordLessThan() { … } ConstantFoldingRule FoldFOrdGreaterThan() { … } ConstantFoldingRule FoldFUnordGreaterThan() { … } ConstantFoldingRule FoldFOrdLessThanEqual() { … } ConstantFoldingRule FoldFUnordLessThanEqual() { … } ConstantFoldingRule FoldFOrdGreaterThanEqual() { … } ConstantFoldingRule FoldFUnordGreaterThanEqual() { … } // Folds an OpDot where all of the inputs are constants to a // constant. A new constant is created if necessary. ConstantFoldingRule FoldOpDotWithConstants() { … } ConstantFoldingRule FoldFNegate() { … } ConstantFoldingRule FoldSNegate() { … } ConstantFoldingRule FoldFClampFeedingCompare(spv::Op cmp_opcode) { … } ConstantFoldingRule FoldFMix() { … } const analysis::Constant* FoldMin(const analysis::Type* result_type, const analysis::Constant* a, const analysis::Constant* b, analysis::ConstantManager*) { … } const analysis::Constant* FoldMax(const analysis::Type* result_type, const analysis::Constant* a, const analysis::Constant* b, analysis::ConstantManager*) { … } // Fold an clamp instruction when all three operands are constant. const analysis::Constant* FoldClamp1( IRContext* context, Instruction* inst, const std::vector<const analysis::Constant*>& constants) { … } // Fold a clamp instruction when |x <= min_val|. const analysis::Constant* FoldClamp2( IRContext* context, Instruction* inst, const std::vector<const analysis::Constant*>& constants) { … } // Fold a clamp instruction when |x >= max_val|. const analysis::Constant* FoldClamp3( IRContext* context, Instruction* inst, const std::vector<const analysis::Constant*>& constants) { … } UnaryScalarFoldingRule FoldFTranscendentalUnary(double (*fp)(double)) { … } BinaryScalarFoldingRule FoldFTranscendentalBinary(double (*fp)(double, double)) { … } enum Sign { … }; // Returns a BinaryScalarFoldingRule that applies `op` to the scalars. // The `signedness` is used to determine if the operands should be interpreted // as signed or unsigned. If the operands are signed, the value will be sign // extended before the value is passed to `op`. Otherwise the values will be // zero extended. template <Sign signedness> BinaryScalarFoldingRule FoldBinaryIntegerOperation(uint64_t (*op)(uint64_t, uint64_t)) { … } // A scalar folding rule that folds OpSConvert. const analysis::Constant* FoldScalarSConvert( const analysis::Type* result_type, const analysis::Constant* a, analysis::ConstantManager* const_mgr) { … } // A scalar folding rule that folds OpUConvert. const analysis::Constant* FoldScalarUConvert( const analysis::Type* result_type, const analysis::Constant* a, analysis::ConstantManager* const_mgr) { … } } // namespace void ConstantFoldingRules::AddFoldingRules() { … } } // namespace opt } // namespace spvtools