SPIRV-Tools/source/opt/const_folding_rules.h
Steven Perron 15fc19d091
Refactor instruction folders (#2815)
* Refactor instruction folders

We want to refactor the instruction folder to allow different sets of
rules to be added to the instruction folder.  We might want different
sets of rules in different circumstances.

We also need a way to add rules for extended instructions.  Changes are
made to the FoldingRules class and ConstFoldingRules class to enable
that.

We added tests to check that we can fold extended instructions using the
new framework.

At the same time, I noticed that there were two tests that did not tests
what they were suppose to.  They could not be easily salvaged. #2813 was
opened to track adding the new tests.
2019-08-26 18:54:11 -04:00

131 lines
4.3 KiB
C++

// 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.
#ifndef SOURCE_OPT_CONST_FOLDING_RULES_H_
#define SOURCE_OPT_CONST_FOLDING_RULES_H_
#include <unordered_map>
#include <vector>
#include "source/opt/constants.h"
namespace spvtools {
namespace opt {
// Constant Folding Rules:
//
// The folding mechanism is built around the concept of a |ConstantFoldingRule|.
// A constant folding rule is a function that implements a method of simplifying
// an instruction to a constant.
//
// The inputs to a folding rule are:
// |inst| - the instruction to be simplified.
// |constants| - if an in-operands is an id of a constant, then the
// corresponding value in |constants| contains that
// constant value. Otherwise, the corresponding entry in
// |constants| is |nullptr|.
//
// A constant folding rule returns a pointer to an Constant if |inst| can be
// simplified using this rule. Otherwise, it returns |nullptr|.
//
// See const_folding_rules.cpp for examples on how to write a constant folding
// rule.
//
// Be sure to add new constant folding rules to the table of constant folding
// rules in the constructor for ConstantFoldingRules. The new rule should be
// added to the list for every opcode that it applies to. Note that earlier
// rules in the list are given priority. That is, if an earlier rule is able to
// fold an instruction, the later rules will not be attempted.
using ConstantFoldingRule = std::function<const analysis::Constant*(
IRContext* ctx, Instruction* inst,
const std::vector<const analysis::Constant*>& constants)>;
class ConstantFoldingRules {
protected:
// The |Key| and |Value| structs are used to by-pass a "decorated name length
// exceeded, name was truncated" warning on VS2013 and VS2015.
struct Key {
uint32_t instruction_set;
uint32_t opcode;
};
friend bool operator<(const Key& a, const Key& b) {
if (a.instruction_set < b.instruction_set) {
return true;
}
if (a.instruction_set > b.instruction_set) {
return false;
}
return a.opcode < b.opcode;
}
struct Value {
std::vector<ConstantFoldingRule> value;
void push_back(ConstantFoldingRule rule) { value.push_back(rule); }
};
public:
ConstantFoldingRules(IRContext* ctx) : context_(ctx) {}
virtual ~ConstantFoldingRules() = default;
// Returns true if there is at least 1 folding rule for |opcode|.
bool HasFoldingRule(const Instruction* inst) const {
return !GetRulesForInstruction(inst).empty();
}
// Returns true if there is at least 1 folding rule for |inst|.
const std::vector<ConstantFoldingRule>& GetRulesForInstruction(
const Instruction* inst) const {
if (inst->opcode() != SpvOpExtInst) {
auto it = rules_.find(inst->opcode());
if (it != rules_.end()) {
return it->second.value;
}
} else {
uint32_t ext_inst_id = inst->GetSingleWordInOperand(0);
uint32_t ext_opcode = inst->GetSingleWordInOperand(1);
auto it = ext_rules_.find({ext_inst_id, ext_opcode});
if (it != ext_rules_.end()) {
return it->second.value;
}
}
return empty_vector_;
}
// Add the folding rules.
virtual void AddFoldingRules();
protected:
// |rules[opcode]| is the set of rules that can be applied to instructions
// with |opcode| as the opcode.
std::unordered_map<uint32_t, Value> rules_;
// The folding rules for extended instructions.
std::map<Key, Value> ext_rules_;
private:
// The context that the instruction to be folded will be a part of.
IRContext* context_;
// The empty set of rules to be used as the default return value in
// |GetRulesForInstruction|.
std::vector<ConstantFoldingRule> empty_vector_;
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_CONST_FOLDING_RULES_H_