| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705 |
- // Copyright (c) 2017 Google 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.
- #include "source/opt/fold.h"
- #include <cassert>
- #include <cstdint>
- #include <vector>
- #include "source/opt/const_folding_rules.h"
- #include "source/opt/def_use_manager.h"
- #include "source/opt/folding_rules.h"
- #include "source/opt/ir_builder.h"
- #include "source/opt/ir_context.h"
- namespace spvtools {
- namespace opt {
- namespace {
- #ifndef INT32_MIN
- #define INT32_MIN (-2147483648)
- #endif
- #ifndef INT32_MAX
- #define INT32_MAX 2147483647
- #endif
- #ifndef UINT32_MAX
- #define UINT32_MAX 0xffffffff /* 4294967295U */
- #endif
- } // namespace
- uint32_t InstructionFolder::UnaryOperate(SpvOp opcode, uint32_t operand) const {
- switch (opcode) {
- // Arthimetics
- case SpvOp::SpvOpSNegate: {
- int32_t s_operand = static_cast<int32_t>(operand);
- if (s_operand == std::numeric_limits<int32_t>::min()) {
- return s_operand;
- }
- return -s_operand;
- }
- case SpvOp::SpvOpNot:
- return ~operand;
- case SpvOp::SpvOpLogicalNot:
- return !static_cast<bool>(operand);
- default:
- assert(false &&
- "Unsupported unary operation for OpSpecConstantOp instruction");
- return 0u;
- }
- }
- uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
- uint32_t b) const {
- switch (opcode) {
- // Arthimetics
- case SpvOp::SpvOpIAdd:
- return a + b;
- case SpvOp::SpvOpISub:
- return a - b;
- case SpvOp::SpvOpIMul:
- return a * b;
- case SpvOp::SpvOpUDiv:
- if (b != 0) {
- return a / b;
- } else {
- // Dividing by 0 is undefined, so we will just pick 0.
- return 0;
- }
- case SpvOp::SpvOpSDiv:
- if (b != 0u) {
- return (static_cast<int32_t>(a)) / (static_cast<int32_t>(b));
- } else {
- // Dividing by 0 is undefined, so we will just pick 0.
- return 0;
- }
- case SpvOp::SpvOpSRem: {
- // The sign of non-zero result comes from the first operand: a. This is
- // guaranteed by C++11 rules for integer division operator. The division
- // result is rounded toward zero, so the result of '%' has the sign of
- // the first operand.
- if (b != 0u) {
- return static_cast<int32_t>(a) % static_cast<int32_t>(b);
- } else {
- // Remainder when dividing with 0 is undefined, so we will just pick 0.
- return 0;
- }
- }
- case SpvOp::SpvOpSMod: {
- // The sign of non-zero result comes from the second operand: b
- if (b != 0u) {
- int32_t rem = BinaryOperate(SpvOp::SpvOpSRem, a, b);
- int32_t b_prim = static_cast<int32_t>(b);
- return (rem + b_prim) % b_prim;
- } else {
- // Mod with 0 is undefined, so we will just pick 0.
- return 0;
- }
- }
- case SpvOp::SpvOpUMod:
- if (b != 0u) {
- return (a % b);
- } else {
- // Mod with 0 is undefined, so we will just pick 0.
- return 0;
- }
- // Shifting
- case SpvOp::SpvOpShiftRightLogical:
- if (b >= 32) {
- // This is undefined behaviour when |b| > 32. Choose 0 for consistency.
- // When |b| == 32, doing the shift in C++ in undefined, but the result
- // will be 0, so just return that value.
- return 0;
- }
- return a >> b;
- case SpvOp::SpvOpShiftRightArithmetic:
- if (b > 32) {
- // This is undefined behaviour. Choose 0 for consistency.
- return 0;
- }
- if (b == 32) {
- // Doing the shift in C++ is undefined, but the result is defined in the
- // spir-v spec. Find that value another way.
- if (static_cast<int32_t>(a) >= 0) {
- return 0;
- } else {
- return static_cast<uint32_t>(-1);
- }
- }
- return (static_cast<int32_t>(a)) >> b;
- case SpvOp::SpvOpShiftLeftLogical:
- if (b >= 32) {
- // This is undefined behaviour when |b| > 32. Choose 0 for consistency.
- // When |b| == 32, doing the shift in C++ in undefined, but the result
- // will be 0, so just return that value.
- return 0;
- }
- return a << b;
- // Bitwise operations
- case SpvOp::SpvOpBitwiseOr:
- return a | b;
- case SpvOp::SpvOpBitwiseAnd:
- return a & b;
- case SpvOp::SpvOpBitwiseXor:
- return a ^ b;
- // Logical
- case SpvOp::SpvOpLogicalEqual:
- return (static_cast<bool>(a)) == (static_cast<bool>(b));
- case SpvOp::SpvOpLogicalNotEqual:
- return (static_cast<bool>(a)) != (static_cast<bool>(b));
- case SpvOp::SpvOpLogicalOr:
- return (static_cast<bool>(a)) || (static_cast<bool>(b));
- case SpvOp::SpvOpLogicalAnd:
- return (static_cast<bool>(a)) && (static_cast<bool>(b));
- // Comparison
- case SpvOp::SpvOpIEqual:
- return a == b;
- case SpvOp::SpvOpINotEqual:
- return a != b;
- case SpvOp::SpvOpULessThan:
- return a < b;
- case SpvOp::SpvOpSLessThan:
- return (static_cast<int32_t>(a)) < (static_cast<int32_t>(b));
- case SpvOp::SpvOpUGreaterThan:
- return a > b;
- case SpvOp::SpvOpSGreaterThan:
- return (static_cast<int32_t>(a)) > (static_cast<int32_t>(b));
- case SpvOp::SpvOpULessThanEqual:
- return a <= b;
- case SpvOp::SpvOpSLessThanEqual:
- return (static_cast<int32_t>(a)) <= (static_cast<int32_t>(b));
- case SpvOp::SpvOpUGreaterThanEqual:
- return a >= b;
- case SpvOp::SpvOpSGreaterThanEqual:
- return (static_cast<int32_t>(a)) >= (static_cast<int32_t>(b));
- default:
- assert(false &&
- "Unsupported binary operation for OpSpecConstantOp instruction");
- return 0u;
- }
- }
- uint32_t InstructionFolder::TernaryOperate(SpvOp opcode, uint32_t a, uint32_t b,
- uint32_t c) const {
- switch (opcode) {
- case SpvOp::SpvOpSelect:
- return (static_cast<bool>(a)) ? b : c;
- default:
- assert(false &&
- "Unsupported ternary operation for OpSpecConstantOp instruction");
- return 0u;
- }
- }
- uint32_t InstructionFolder::OperateWords(
- SpvOp opcode, const std::vector<uint32_t>& operand_words) const {
- switch (operand_words.size()) {
- case 1:
- return UnaryOperate(opcode, operand_words.front());
- case 2:
- return BinaryOperate(opcode, operand_words.front(), operand_words.back());
- case 3:
- return TernaryOperate(opcode, operand_words[0], operand_words[1],
- operand_words[2]);
- default:
- assert(false && "Invalid number of operands");
- return 0;
- }
- }
- bool InstructionFolder::FoldInstructionInternal(Instruction* inst) const {
- auto identity_map = [](uint32_t id) { return id; };
- Instruction* folded_inst = FoldInstructionToConstant(inst, identity_map);
- if (folded_inst != nullptr) {
- inst->SetOpcode(SpvOpCopyObject);
- inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {folded_inst->result_id()}}});
- return true;
- }
- analysis::ConstantManager* const_manager = context_->get_constant_mgr();
- std::vector<const analysis::Constant*> constants =
- const_manager->GetOperandConstants(inst);
- for (const FoldingRule& rule :
- GetFoldingRules().GetRulesForInstruction(inst)) {
- if (rule(context_, inst, constants)) {
- return true;
- }
- }
- return false;
- }
- // Returns the result of performing an operation on scalar constant operands.
- // This function extracts the operand values as 32 bit words and returns the
- // result in 32 bit word. Scalar constants with longer than 32-bit width are
- // not accepted in this function.
- uint32_t InstructionFolder::FoldScalars(
- SpvOp opcode,
- const std::vector<const analysis::Constant*>& operands) const {
- assert(IsFoldableOpcode(opcode) &&
- "Unhandled instruction opcode in FoldScalars");
- std::vector<uint32_t> operand_values_in_raw_words;
- for (const auto& operand : operands) {
- if (const analysis::ScalarConstant* scalar = operand->AsScalarConstant()) {
- const auto& scalar_words = scalar->words();
- assert(scalar_words.size() == 1 &&
- "Scalar constants with longer than 32-bit width are not allowed "
- "in FoldScalars()");
- operand_values_in_raw_words.push_back(scalar_words.front());
- } else if (operand->AsNullConstant()) {
- operand_values_in_raw_words.push_back(0u);
- } else {
- assert(false &&
- "FoldScalars() only accepts ScalarConst or NullConst type of "
- "constant");
- }
- }
- return OperateWords(opcode, operand_values_in_raw_words);
- }
- bool InstructionFolder::FoldBinaryIntegerOpToConstant(
- Instruction* inst, const std::function<uint32_t(uint32_t)>& id_map,
- uint32_t* result) const {
- SpvOp opcode = inst->opcode();
- analysis::ConstantManager* const_manger = context_->get_constant_mgr();
- uint32_t ids[2];
- const analysis::IntConstant* constants[2];
- for (uint32_t i = 0; i < 2; i++) {
- const Operand* operand = &inst->GetInOperand(i);
- if (operand->type != SPV_OPERAND_TYPE_ID) {
- return false;
- }
- ids[i] = id_map(operand->words[0]);
- const analysis::Constant* constant =
- const_manger->FindDeclaredConstant(ids[i]);
- constants[i] = (constant != nullptr ? constant->AsIntConstant() : nullptr);
- }
- switch (opcode) {
- // Arthimetics
- case SpvOp::SpvOpIMul:
- for (uint32_t i = 0; i < 2; i++) {
- if (constants[i] != nullptr && constants[i]->IsZero()) {
- *result = 0;
- return true;
- }
- }
- break;
- case SpvOp::SpvOpUDiv:
- case SpvOp::SpvOpSDiv:
- case SpvOp::SpvOpSRem:
- case SpvOp::SpvOpSMod:
- case SpvOp::SpvOpUMod:
- // This changes undefined behaviour (ie divide by 0) into a 0.
- for (uint32_t i = 0; i < 2; i++) {
- if (constants[i] != nullptr && constants[i]->IsZero()) {
- *result = 0;
- return true;
- }
- }
- break;
- // Shifting
- case SpvOp::SpvOpShiftRightLogical:
- case SpvOp::SpvOpShiftLeftLogical:
- if (constants[1] != nullptr) {
- // When shifting by a value larger than the size of the result, the
- // result is undefined. We are setting the undefined behaviour to a
- // result of 0. If the shift amount is the same as the size of the
- // result, then the result is defined, and it 0.
- uint32_t shift_amount = constants[1]->GetU32BitValue();
- if (shift_amount >= 32) {
- *result = 0;
- return true;
- }
- }
- break;
- // Bitwise operations
- case SpvOp::SpvOpBitwiseOr:
- for (uint32_t i = 0; i < 2; i++) {
- if (constants[i] != nullptr) {
- // TODO: Change the mask against a value based on the bit width of the
- // instruction result type. This way we can handle say 16-bit values
- // as well.
- uint32_t mask = constants[i]->GetU32BitValue();
- if (mask == 0xFFFFFFFF) {
- *result = 0xFFFFFFFF;
- return true;
- }
- }
- }
- break;
- case SpvOp::SpvOpBitwiseAnd:
- for (uint32_t i = 0; i < 2; i++) {
- if (constants[i] != nullptr) {
- if (constants[i]->IsZero()) {
- *result = 0;
- return true;
- }
- }
- }
- break;
- // Comparison
- case SpvOp::SpvOpULessThan:
- if (constants[0] != nullptr &&
- constants[0]->GetU32BitValue() == UINT32_MAX) {
- *result = false;
- return true;
- }
- if (constants[1] != nullptr && constants[1]->GetU32BitValue() == 0) {
- *result = false;
- return true;
- }
- break;
- case SpvOp::SpvOpSLessThan:
- if (constants[0] != nullptr &&
- constants[0]->GetS32BitValue() == INT32_MAX) {
- *result = false;
- return true;
- }
- if (constants[1] != nullptr &&
- constants[1]->GetS32BitValue() == INT32_MIN) {
- *result = false;
- return true;
- }
- break;
- case SpvOp::SpvOpUGreaterThan:
- if (constants[0] != nullptr && constants[0]->IsZero()) {
- *result = false;
- return true;
- }
- if (constants[1] != nullptr &&
- constants[1]->GetU32BitValue() == UINT32_MAX) {
- *result = false;
- return true;
- }
- break;
- case SpvOp::SpvOpSGreaterThan:
- if (constants[0] != nullptr &&
- constants[0]->GetS32BitValue() == INT32_MIN) {
- *result = false;
- return true;
- }
- if (constants[1] != nullptr &&
- constants[1]->GetS32BitValue() == INT32_MAX) {
- *result = false;
- return true;
- }
- break;
- case SpvOp::SpvOpULessThanEqual:
- if (constants[0] != nullptr && constants[0]->IsZero()) {
- *result = true;
- return true;
- }
- if (constants[1] != nullptr &&
- constants[1]->GetU32BitValue() == UINT32_MAX) {
- *result = true;
- return true;
- }
- break;
- case SpvOp::SpvOpSLessThanEqual:
- if (constants[0] != nullptr &&
- constants[0]->GetS32BitValue() == INT32_MIN) {
- *result = true;
- return true;
- }
- if (constants[1] != nullptr &&
- constants[1]->GetS32BitValue() == INT32_MAX) {
- *result = true;
- return true;
- }
- break;
- case SpvOp::SpvOpUGreaterThanEqual:
- if (constants[0] != nullptr &&
- constants[0]->GetU32BitValue() == UINT32_MAX) {
- *result = true;
- return true;
- }
- if (constants[1] != nullptr && constants[1]->GetU32BitValue() == 0) {
- *result = true;
- return true;
- }
- break;
- case SpvOp::SpvOpSGreaterThanEqual:
- if (constants[0] != nullptr &&
- constants[0]->GetS32BitValue() == INT32_MAX) {
- *result = true;
- return true;
- }
- if (constants[1] != nullptr &&
- constants[1]->GetS32BitValue() == INT32_MIN) {
- *result = true;
- return true;
- }
- break;
- default:
- break;
- }
- return false;
- }
- bool InstructionFolder::FoldBinaryBooleanOpToConstant(
- Instruction* inst, const std::function<uint32_t(uint32_t)>& id_map,
- uint32_t* result) const {
- SpvOp opcode = inst->opcode();
- analysis::ConstantManager* const_manger = context_->get_constant_mgr();
- uint32_t ids[2];
- const analysis::BoolConstant* constants[2];
- for (uint32_t i = 0; i < 2; i++) {
- const Operand* operand = &inst->GetInOperand(i);
- if (operand->type != SPV_OPERAND_TYPE_ID) {
- return false;
- }
- ids[i] = id_map(operand->words[0]);
- const analysis::Constant* constant =
- const_manger->FindDeclaredConstant(ids[i]);
- constants[i] = (constant != nullptr ? constant->AsBoolConstant() : nullptr);
- }
- switch (opcode) {
- // Logical
- case SpvOp::SpvOpLogicalOr:
- for (uint32_t i = 0; i < 2; i++) {
- if (constants[i] != nullptr) {
- if (constants[i]->value()) {
- *result = true;
- return true;
- }
- }
- }
- break;
- case SpvOp::SpvOpLogicalAnd:
- for (uint32_t i = 0; i < 2; i++) {
- if (constants[i] != nullptr) {
- if (!constants[i]->value()) {
- *result = false;
- return true;
- }
- }
- }
- break;
- default:
- break;
- }
- return false;
- }
- bool InstructionFolder::FoldIntegerOpToConstant(
- Instruction* inst, const std::function<uint32_t(uint32_t)>& id_map,
- uint32_t* result) const {
- assert(IsFoldableOpcode(inst->opcode()) &&
- "Unhandled instruction opcode in FoldScalars");
- switch (inst->NumInOperands()) {
- case 2:
- return FoldBinaryIntegerOpToConstant(inst, id_map, result) ||
- FoldBinaryBooleanOpToConstant(inst, id_map, result);
- default:
- return false;
- }
- }
- std::vector<uint32_t> InstructionFolder::FoldVectors(
- SpvOp opcode, uint32_t num_dims,
- const std::vector<const analysis::Constant*>& operands) const {
- assert(IsFoldableOpcode(opcode) &&
- "Unhandled instruction opcode in FoldVectors");
- std::vector<uint32_t> result;
- for (uint32_t d = 0; d < num_dims; d++) {
- std::vector<uint32_t> operand_values_for_one_dimension;
- for (const auto& operand : operands) {
- if (const analysis::VectorConstant* vector_operand =
- operand->AsVectorConstant()) {
- // Extract the raw value of the scalar component constants
- // in 32-bit words here. The reason of not using FoldScalars() here
- // is that we do not create temporary null constants as components
- // when the vector operand is a NullConstant because Constant creation
- // may need extra checks for the validity and that is not manageed in
- // here.
- if (const analysis::ScalarConstant* scalar_component =
- vector_operand->GetComponents().at(d)->AsScalarConstant()) {
- const auto& scalar_words = scalar_component->words();
- assert(
- scalar_words.size() == 1 &&
- "Vector components with longer than 32-bit width are not allowed "
- "in FoldVectors()");
- operand_values_for_one_dimension.push_back(scalar_words.front());
- } else if (operand->AsNullConstant()) {
- operand_values_for_one_dimension.push_back(0u);
- } else {
- assert(false &&
- "VectorConst should only has ScalarConst or NullConst as "
- "components");
- }
- } else if (operand->AsNullConstant()) {
- operand_values_for_one_dimension.push_back(0u);
- } else {
- assert(false &&
- "FoldVectors() only accepts VectorConst or NullConst type of "
- "constant");
- }
- }
- result.push_back(OperateWords(opcode, operand_values_for_one_dimension));
- }
- return result;
- }
- bool InstructionFolder::IsFoldableOpcode(SpvOp opcode) const {
- // NOTE: Extend to more opcodes as new cases are handled in the folder
- // functions.
- switch (opcode) {
- case SpvOp::SpvOpBitwiseAnd:
- case SpvOp::SpvOpBitwiseOr:
- case SpvOp::SpvOpBitwiseXor:
- case SpvOp::SpvOpIAdd:
- case SpvOp::SpvOpIEqual:
- case SpvOp::SpvOpIMul:
- case SpvOp::SpvOpINotEqual:
- case SpvOp::SpvOpISub:
- case SpvOp::SpvOpLogicalAnd:
- case SpvOp::SpvOpLogicalEqual:
- case SpvOp::SpvOpLogicalNot:
- case SpvOp::SpvOpLogicalNotEqual:
- case SpvOp::SpvOpLogicalOr:
- case SpvOp::SpvOpNot:
- case SpvOp::SpvOpSDiv:
- case SpvOp::SpvOpSelect:
- case SpvOp::SpvOpSGreaterThan:
- case SpvOp::SpvOpSGreaterThanEqual:
- case SpvOp::SpvOpShiftLeftLogical:
- case SpvOp::SpvOpShiftRightArithmetic:
- case SpvOp::SpvOpShiftRightLogical:
- case SpvOp::SpvOpSLessThan:
- case SpvOp::SpvOpSLessThanEqual:
- case SpvOp::SpvOpSMod:
- case SpvOp::SpvOpSNegate:
- case SpvOp::SpvOpSRem:
- case SpvOp::SpvOpUDiv:
- case SpvOp::SpvOpUGreaterThan:
- case SpvOp::SpvOpUGreaterThanEqual:
- case SpvOp::SpvOpULessThan:
- case SpvOp::SpvOpULessThanEqual:
- case SpvOp::SpvOpUMod:
- return true;
- default:
- return false;
- }
- }
- bool InstructionFolder::IsFoldableConstant(
- const analysis::Constant* cst) const {
- // Currently supported constants are 32-bit values or null constants.
- if (const analysis::ScalarConstant* scalar = cst->AsScalarConstant())
- return scalar->words().size() == 1;
- else
- return cst->AsNullConstant() != nullptr;
- }
- Instruction* InstructionFolder::FoldInstructionToConstant(
- Instruction* inst, std::function<uint32_t(uint32_t)> id_map) const {
- analysis::ConstantManager* const_mgr = context_->get_constant_mgr();
- if (!inst->IsFoldableByFoldScalar() &&
- !GetConstantFoldingRules().HasFoldingRule(inst)) {
- return nullptr;
- }
- // Collect the values of the constant parameters.
- std::vector<const analysis::Constant*> constants;
- bool missing_constants = false;
- inst->ForEachInId([&constants, &missing_constants, const_mgr,
- &id_map](uint32_t* op_id) {
- uint32_t id = id_map(*op_id);
- const analysis::Constant* const_op = const_mgr->FindDeclaredConstant(id);
- if (!const_op) {
- constants.push_back(nullptr);
- missing_constants = true;
- } else {
- constants.push_back(const_op);
- }
- });
- const analysis::Constant* folded_const = nullptr;
- for (auto rule : GetConstantFoldingRules().GetRulesForInstruction(inst)) {
- folded_const = rule(context_, inst, constants);
- if (folded_const != nullptr) {
- Instruction* const_inst =
- const_mgr->GetDefiningInstruction(folded_const, inst->type_id());
- if (const_inst == nullptr) {
- return nullptr;
- }
- assert(const_inst->type_id() == inst->type_id());
- // May be a new instruction that needs to be analysed.
- context_->UpdateDefUse(const_inst);
- return const_inst;
- }
- }
- uint32_t result_val = 0;
- bool successful = false;
- // If all parameters are constant, fold the instruction to a constant.
- if (!missing_constants && inst->IsFoldableByFoldScalar()) {
- result_val = FoldScalars(inst->opcode(), constants);
- successful = true;
- }
- if (!successful && inst->IsFoldableByFoldScalar()) {
- successful = FoldIntegerOpToConstant(inst, id_map, &result_val);
- }
- if (successful) {
- const analysis::Constant* result_const =
- const_mgr->GetConstant(const_mgr->GetType(inst), {result_val});
- Instruction* folded_inst =
- const_mgr->GetDefiningInstruction(result_const, inst->type_id());
- return folded_inst;
- }
- return nullptr;
- }
- bool InstructionFolder::IsFoldableType(Instruction* type_inst) const {
- // Support 32-bit integers.
- if (type_inst->opcode() == SpvOpTypeInt) {
- return type_inst->GetSingleWordInOperand(0) == 32;
- }
- // Support booleans.
- if (type_inst->opcode() == SpvOpTypeBool) {
- return true;
- }
- // Nothing else yet.
- return false;
- }
- bool InstructionFolder::FoldInstruction(Instruction* inst) const {
- bool modified = false;
- Instruction* folded_inst(inst);
- while (folded_inst->opcode() != SpvOpCopyObject &&
- FoldInstructionInternal(&*folded_inst)) {
- modified = true;
- }
- return modified;
- }
- } // namespace opt
- } // namespace spvtools
|