Coverage Report

Created: 2023-12-11 06:17

/proc/self/cwd/src/ir/module.h
Line
Count
Source (jump to first uncovered line)
1
//-----------------------------------------------------------------------------
2
// Copyright 2022 Google LLC
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
//
8
//     https://www.apache.org/licenses/LICENSE-2.0
9
//
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
//----------------------------------------------------------------------------
16
#ifndef SRC_IR_MODULE_H_
17
#define SRC_IR_MODULE_H_
18
19
#include <cstdint>
20
#include <vector>
21
22
#include "absl/strings/string_view.h"
23
#include "src/ir/attributes/attribute.h"
24
#include "src/ir/data_decl.h"
25
#include "src/ir/ir_visitor.h"
26
#include "src/ir/operator.h"
27
#include "src/ir/storage.h"
28
#include "src/ir/types/type.h"
29
#include "src/ir/value.h"
30
31
namespace raksha::ir {
32
33
class Module;
34
class Block;
35
36
// An Operation represents a unit of execution.
37
class Operation {
38
 public:
39
  Operation(const Block* parent, const Operator& op,
40
            NamedAttributeMap attributes, ValueList inputs)
41
      : parent_(parent),
42
        op_(std::addressof(op)),
43
        attributes_(std::move(attributes)),
44
0
        inputs_(std::move(inputs)) {}
45
46
  Operation(const Operator& op, NamedAttributeMap attributes, ValueList inputs)
47
0
      : Operation(nullptr, op, attributes, inputs) {}
48
49
0
  Operation(const Operator& op) : Operation(nullptr, op, {}, {}) {}
50
51
  // Disable copy semantics.
52
  Operation(const Operation&) = delete;
53
  Operation& operator=(const Operation&) = delete;
54
  Operation(Operation&&) = default;
55
  Operation& operator=(Operation&&) = default;
56
57
0
  virtual ~Operation() {}
58
59
0
  const Operator& op() const { return *op_; }
60
0
  const Block* parent() const { return parent_; }
61
0
  const ValueList& inputs() const { return inputs_; }
62
0
  const NamedAttributeMap& attributes() const { return attributes_; }
63
64
0
  const Value& GetInputValue(uint64_t index) const {
65
0
    CHECK(index < inputs_.size())
66
0
        << "Operation:GetInputValue fails because index is out of bounds";
67
0
    return inputs_[index];
68
0
  }
69
0
  uint64_t NumberOfOutputs() const { return op_->number_of_return_values(); }
70
71
0
  Value GetOutputValue(uint64_t index) const {
72
0
    CHECK(index < op_->number_of_return_values())
73
0
        << "Operation:GetOutputValue fails because index is out of bounds";
74
0
    return Value::MakeOperationResultValue(*this, index);
75
0
  }
76
77
  template <typename Derived, typename Result>
78
  Result Accept(IRVisitor<Derived, Result, false>& visitor) {
79
    return visitor.Visit(*this);
80
  }
81
82
  template <typename Derived, typename Result>
83
  Result Accept(IRVisitor<Derived, Result, true>& visitor) const {
84
    return visitor.Visit(*this);
85
  }
86
0
  void AddInput(const Value& value) { inputs_.push_back(value); }
87
0
  void AddAttribute(const std::string name, const Attribute& value) {
88
0
    attributes_.emplace(name, value);
89
0
  }
90
0
  void set_parent(const Block* parent) { parent_ = parent; }
91
92
 private:
93
  // The parent block if any to which this operation belongs to.
94
  const Block* parent_;
95
  // The operator being executed.
96
  const Operator* op_;
97
  // The attributes of the operation.
98
  NamedAttributeMap attributes_;
99
  // The inputs of the operation.
100
  ValueList inputs_;
101
};
102
103
// A collection of operations.
104
class Block {
105
 public:
106
  // The type for a collection of `Operation` instances.
107
  using OperationList = std::vector<std::unique_ptr<Operation>>;
108
109
0
  Block() : parent_module_(nullptr) {}
110
111
  // Disable copy semantics.
112
  Block(const Block&) = delete;
113
  Block& operator=(const Block&) = delete;
114
  Block(Block&&) = default;
115
  Block& operator=(Block&&) = default;
116
0
  ~Block() = default;
117
118
0
  const OperationList& operations() const { return operations_; }
119
0
  const DataDeclCollection& inputs() const { return inputs_; }
120
0
  const DataDeclCollection& outputs() const { return outputs_; }
121
0
  const IndexedValueMap& results() const { return results_; }
122
0
  const Module* parent_module() const { return parent_module_; }
123
124
  template <typename Derived, typename Result>
125
  Result Accept(IRVisitor<Derived, Result, false>& visitor) {
126
    return visitor.Visit(*this);
127
  }
128
129
  template <typename Derived, typename Result>
130
  Result Accept(IRVisitor<Derived, Result, true>& visitor) const {
131
    return visitor.Visit(*this);
132
  }
133
134
  friend class BlockBuilder;
135
  friend class Module;
136
137
 private:
138
  // Set the module to which this block belongs. This is private so that only
139
  // the Module can set it via its `AddBlock` function.
140
0
  void set_parent_module(const Module& module) { parent_module_ = &module; }
141
142
  // Module to which this belongs to.
143
  const Module* parent_module_;
144
  // The inputs to this block.
145
  DataDeclCollection inputs_;
146
  // Outputs from this block.
147
  DataDeclCollection outputs_;
148
  // The list of operations that belong to this block. This can be empty.
149
  OperationList operations_;
150
  // Maps the outputs of the operations in the list of operations in this
151
  // block to the corresponding name. Note that a result can have more than
152
  // one value which is used to represent non-determinism.
153
  IndexedValueMap results_;
154
};
155
156
// A class that contains a collection of blocks.
157
class Module {
158
 public:
159
  using BlockListType = std::vector<std::unique_ptr<Block>>;
160
  using NamedStorageMap =
161
      absl::flat_hash_map<std::string, std::unique_ptr<Storage>>;
162
163
4.43k
  Module() {}
164
  // Make the class move-only.
165
  Module(const Module&) = delete;
166
  Module& operator=(const Module&) = delete;
167
  Module(Module&&) = default;
168
  Module& operator=(Module&&) = default;
169
4.43k
  ~Module() = default;
170
171
  // Adds a block to the module and returns a pointer to it.
172
0
  const Block& AddBlock(std::unique_ptr<Block> block) {
173
    // Note: this check should be impossible due to this function taking a
174
    // `unique_ptr` to the `Block`. But it's a cheap thing to check, so might
175
    // as well just do it.
176
0
    CHECK(block->parent_module() == nullptr) << "Attempt to add a Block to two "
177
0
                                                "different Modules!";
178
0
    block->set_parent_module(*this);
179
0
    blocks_.push_back(std::move(block));
180
0
    return *blocks_.back();
181
0
  }
182
183
  // Creates a `Storage` in the `Module` with the given name and type. We expect
184
  // `Storage`s to be declared in a `Module` before they are actually used, so
185
  // we expect that the `Storage`'s `input_value`s will be filled in later,
186
  // which is why we return a mutable reference.
187
124k
  const Storage& CreateStorage(absl::string_view name, ir::types::Type type) {
188
124k
    auto insert_result = named_storage_map_.insert(
189
124k
        {std::string(name), std::make_unique<Storage>(name, type)});
190
124k
    CHECK(insert_result.second)
191
124k
        << "Multiple stores with name " << insert_result.first->first;
192
124k
    return *insert_result.first->second;
193
124k
  }
194
195
  // Get the `Storage` associated with `name` in this `Module`.
196
  //
197
  // This method fails if the name is not present in this module.
198
26.7k
  const Storage& GetStorage(absl::string_view name) const {
199
26.7k
    auto find_result = named_storage_map_.find(name);
200
26.7k
    CHECK(find_result != named_storage_map_.end())
201
26.7k
        << "Could not find Storage with name " << name;
202
26.7k
    return *find_result->second;
203
26.7k
  }
204
205
947
  void AddInputValueToStorage(absl::string_view storage_name, Value value) {
206
947
    auto find_result = named_storage_map_.find(storage_name);
207
947
    CHECK(find_result != named_storage_map_.end());
208
947
    find_result->second->AddInputValue(value);
209
947
  }
210
211
0
  const BlockListType& blocks() const { return blocks_; }
212
2.60k
  const NamedStorageMap& named_storage_map() const {
213
2.60k
    return named_storage_map_;
214
2.60k
  }
215
216
  template <typename Derived, typename Result>
217
  Result Accept(IRVisitor<Derived, Result, false>& visitor) {
218
    return visitor.Visit(*this);
219
  }
220
221
  template <typename Derived, typename Result>
222
  Result Accept(IRVisitor<Derived, Result, true>& visitor) const {
223
    return visitor.Visit(*this);
224
  }
225
226
 private:
227
  BlockListType blocks_;
228
  NamedStorageMap named_storage_map_;
229
};
230
231
}  // namespace raksha::ir
232
233
#endif  // SRC_IR_MODULE_H_