• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SOURCE_OPT_MODULE_H_
16 #define SOURCE_OPT_MODULE_H_
17 
18 #include <functional>
19 #include <memory>
20 #include <string_view>
21 #include <unordered_map>
22 #include <utility>
23 #include <vector>
24 
25 #include "source/opt/function.h"
26 #include "source/opt/instruction.h"
27 #include "source/opt/iterator.h"
28 
29 namespace spvtools {
30 namespace opt {
31 
32 class IRContext;
33 
34 // A struct for containing the module header information.
35 struct ModuleHeader {
36   uint32_t magic_number;
37   uint32_t version;
38   uint32_t generator;
39   uint32_t bound;
40   uint32_t schema;
41 };
42 
43 // A SPIR-V module. It contains all the information for a SPIR-V module and
44 // serves as the backbone of optimization transformations.
45 class Module {
46  public:
47   using iterator = UptrVectorIterator<Function>;
48   using const_iterator = UptrVectorIterator<Function, true>;
49   using inst_iterator = InstructionList::iterator;
50   using const_inst_iterator = InstructionList::const_iterator;
51 
52   // Creates an empty module with zero'd header.
Module()53   Module() : header_({}), contains_debug_info_(false) {}
54 
55   // Sets the header to the given |header|.
SetHeader(const ModuleHeader & header)56   void SetHeader(const ModuleHeader& header) { header_ = header; }
57 
58   // Sets the Id bound.  The Id bound cannot be set to 0.
SetIdBound(uint32_t bound)59   void SetIdBound(uint32_t bound) {
60     assert(bound != 0);
61     header_.bound = bound;
62   }
63 
64   // Returns the Id bound.
IdBound()65   uint32_t IdBound() const { return header_.bound; }
66 
67   // Returns the current Id bound and increases it to the next available value.
68   // If the id bound has already reached its maximum value, then 0 is returned.
69   // The maximum value for the id bound is obtained from the context.  If there
70   // is none, then the minimum that limit can be according to the spir-v
71   // specification.
72   // TODO(1841): Update the uses to check for a 0 return value.
73   uint32_t TakeNextIdBound();
74 
75   // Appends a capability instruction to this module.
76   inline void AddCapability(std::unique_ptr<Instruction> c);
77 
78   // Appends an extension instruction to this module.
79   inline void AddExtension(std::unique_ptr<Instruction> e);
80 
81   // Appends an extended instruction set instruction to this module.
82   inline void AddExtInstImport(std::unique_ptr<Instruction> e);
83 
84   // Set the memory model for this module.
85   inline void SetMemoryModel(std::unique_ptr<Instruction> m);
86 
87   // Set the sampled image addressing mode for this module.
88   inline void SetSampledImageAddressMode(std::unique_ptr<Instruction> m);
89 
90   // Appends an entry point instruction to this module.
91   inline void AddEntryPoint(std::unique_ptr<Instruction> e);
92 
93   // Appends an execution mode instruction to this module.
94   inline void AddExecutionMode(std::unique_ptr<Instruction> e);
95 
96   // Appends a debug 1 instruction (excluding OpLine & OpNoLine) to this module.
97   // "debug 1" instructions are the ones in layout section 7.a), see section
98   // 2.4 Logical Layout of a Module from the SPIR-V specification.
99   inline void AddDebug1Inst(std::unique_ptr<Instruction> d);
100 
101   // Appends a debug 2 instruction (excluding OpLine & OpNoLine) to this module.
102   // "debug 2" instructions are the ones in layout section 7.b), see section
103   // 2.4 Logical Layout of a Module from the SPIR-V specification.
104   inline void AddDebug2Inst(std::unique_ptr<Instruction> d);
105 
106   // Appends a debug 3 instruction (OpModuleProcessed) to this module.
107   // This is due to decision by the SPIR Working Group, pending publication.
108   inline void AddDebug3Inst(std::unique_ptr<Instruction> d);
109 
110   // Appends a debug info extension (OpenCL.DebugInfo.100,
111   // NonSemantic.Shader.DebugInfo.100, or DebugInfo) instruction to this module.
112   inline void AddExtInstDebugInfo(std::unique_ptr<Instruction> d);
113 
114   // Appends an annotation instruction to this module.
115   inline void AddAnnotationInst(std::unique_ptr<Instruction> a);
116 
117   // Appends a type-declaration instruction to this module.
118   inline void AddType(std::unique_ptr<Instruction> t);
119 
120   // Appends a constant, global variable, or OpUndef instruction to this module.
121   inline void AddGlobalValue(std::unique_ptr<Instruction> v);
122 
123   // Prepends a function declaration to this module.
124   inline void AddFunctionDeclaration(std::unique_ptr<Function> f);
125 
126   // Appends a function to this module.
127   inline void AddFunction(std::unique_ptr<Function> f);
128 
129   // Sets |contains_debug_info_| as true.
130   inline void SetContainsDebugInfo();
ContainsDebugInfo()131   inline bool ContainsDebugInfo() { return contains_debug_info_; }
132 
133   // Returns a vector of pointers to type-declaration instructions in this
134   // module.
135   std::vector<Instruction*> GetTypes();
136   std::vector<const Instruction*> GetTypes() const;
137   // Returns a vector of pointers to constant-creation instructions in this
138   // module.
139   std::vector<Instruction*> GetConstants();
140   std::vector<const Instruction*> GetConstants() const;
141 
142   // Return result id of global value with |opcode|, 0 if not present.
143   uint32_t GetGlobalValue(spv::Op opcode) const;
144 
145   // Add global value with |opcode|, |result_id| and |type_id|
146   void AddGlobalValue(spv::Op opcode, uint32_t result_id, uint32_t type_id);
147 
id_bound()148   inline uint32_t id_bound() const { return header_.bound; }
149 
version()150   inline uint32_t version() const { return header_.version; }
generator()151   inline uint32_t generator() const { return header_.generator; }
schema()152   inline uint32_t schema() const { return header_.schema; }
153 
set_version(uint32_t v)154   inline void set_version(uint32_t v) { header_.version = v; }
155 
156   // Iterators for capabilities instructions contained in this module.
157   inline inst_iterator capability_begin();
158   inline inst_iterator capability_end();
159   inline IteratorRange<inst_iterator> capabilities();
160   inline IteratorRange<const_inst_iterator> capabilities() const;
161 
162   // Iterators for ext_inst_imports instructions contained in this module.
163   inline inst_iterator ext_inst_import_begin();
164   inline inst_iterator ext_inst_import_end();
165   inline IteratorRange<inst_iterator> ext_inst_imports();
166   inline IteratorRange<const_inst_iterator> ext_inst_imports() const;
167 
168   // Return the memory model instruction contained in this module.
GetMemoryModel()169   inline Instruction* GetMemoryModel() { return memory_model_.get(); }
GetMemoryModel()170   inline const Instruction* GetMemoryModel() const {
171     return memory_model_.get();
172   }
173 
174   // Return the sampled image address mode instruction contained in this module.
GetSampledImageAddressMode()175   inline Instruction* GetSampledImageAddressMode() {
176     return sampled_image_address_mode_.get();
177   }
GetSampledImageAddressMode()178   inline const Instruction* GetSampledImageAddressMode() const {
179     return sampled_image_address_mode_.get();
180   }
181 
182   // There are several kinds of debug instructions, according to where they can
183   // appear in the logical layout of a module:
184   //  - Section 7a:  OpString, OpSourceExtension, OpSource, OpSourceContinued
185   //  - Section 7b:  OpName, OpMemberName
186   //  - Section 7c:  OpModuleProcessed
187   //  - Mostly anywhere: OpLine and OpNoLine
188   //
189 
190   // Iterators for debug 1 instructions (excluding OpLine & OpNoLine) contained
191   // in this module.  These are for layout section 7a.
192   inline inst_iterator debug1_begin();
193   inline inst_iterator debug1_end();
194   inline IteratorRange<inst_iterator> debugs1();
195   inline IteratorRange<const_inst_iterator> debugs1() const;
196 
197   // Iterators for debug 2 instructions (excluding OpLine & OpNoLine) contained
198   // in this module.  These are for layout section 7b.
199   inline inst_iterator debug2_begin();
200   inline inst_iterator debug2_end();
201   inline IteratorRange<inst_iterator> debugs2();
202   inline IteratorRange<const_inst_iterator> debugs2() const;
203 
204   // Iterators for debug 3 instructions (excluding OpLine & OpNoLine) contained
205   // in this module.  These are for layout section 7c.
206   inline inst_iterator debug3_begin();
207   inline inst_iterator debug3_end();
208   inline IteratorRange<inst_iterator> debugs3();
209   inline IteratorRange<const_inst_iterator> debugs3() const;
210 
211   // Iterators for debug info instructions (excluding OpLine & OpNoLine)
212   // contained in this module.  These are OpExtInst for DebugInfo extension
213   // placed between section 9 and 10.
214   inline inst_iterator ext_inst_debuginfo_begin();
215   inline inst_iterator ext_inst_debuginfo_end();
216   inline IteratorRange<inst_iterator> ext_inst_debuginfo();
217   inline IteratorRange<const_inst_iterator> ext_inst_debuginfo() const;
218 
219   // Iterators for entry point instructions contained in this module
220   inline IteratorRange<inst_iterator> entry_points();
221   inline IteratorRange<const_inst_iterator> entry_points() const;
222 
223   // Iterators for execution_modes instructions contained in this module.
224   inline inst_iterator execution_mode_begin();
225   inline inst_iterator execution_mode_end();
226   inline IteratorRange<inst_iterator> execution_modes();
227   inline IteratorRange<const_inst_iterator> execution_modes() const;
228 
229   // Iterators for annotation instructions contained in this module.
230   inline inst_iterator annotation_begin();
231   inline inst_iterator annotation_end();
232   IteratorRange<inst_iterator> annotations();
233   IteratorRange<const_inst_iterator> annotations() const;
234 
235   // Iterators for extension instructions contained in this module.
236   inline inst_iterator extension_begin();
237   inline inst_iterator extension_end();
238   IteratorRange<inst_iterator> extensions();
239   IteratorRange<const_inst_iterator> extensions() const;
240 
241   // Iterators for types, constants and global variables instructions.
242   inline inst_iterator types_values_begin();
243   inline inst_iterator types_values_end();
244   inline IteratorRange<inst_iterator> types_values();
245   inline IteratorRange<const_inst_iterator> types_values() const;
246 
247   // Iterators for functions contained in this module.
begin()248   iterator begin() { return iterator(&functions_, functions_.begin()); }
end()249   iterator end() { return iterator(&functions_, functions_.end()); }
begin()250   const_iterator begin() const { return cbegin(); }
end()251   const_iterator end() const { return cend(); }
252   inline const_iterator cbegin() const;
253   inline const_iterator cend() const;
254 
255   // Invokes function |f| on all instructions in this module, and optionally on
256   // the debug line instructions that precede them.
257   void ForEachInst(const std::function<void(Instruction*)>& f,
258                    bool run_on_debug_line_insts = false);
259   void ForEachInst(const std::function<void(const Instruction*)>& f,
260                    bool run_on_debug_line_insts = false) const;
261 
262   // Pushes the binary segments for this instruction into the back of *|binary|.
263   // If |skip_nop| is true and this is a OpNop, do nothing.
264   void ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const;
265 
266   // Returns 1 more than the maximum Id value mentioned in the module.
267   uint32_t ComputeIdBound() const;
268 
269   // Returns true if module has capability |cap|
270   bool HasExplicitCapability(uint32_t cap);
271 
272   // Returns id for OpExtInst instruction for extension |extstr|.
273   // Returns 0 if not found.
274   uint32_t GetExtInstImportId(const char* extstr);
275 
276   // Sets the associated context for this module
SetContext(IRContext * c)277   void SetContext(IRContext* c) { context_ = c; }
278 
279   // Gets the associated context for this module
context()280   IRContext* context() const { return context_; }
281 
282   // Sets the trailing debug line info to |dbg_line_info|.
SetTrailingDbgLineInfo(std::vector<Instruction> && dbg_line_info)283   void SetTrailingDbgLineInfo(std::vector<Instruction>&& dbg_line_info) {
284     trailing_dbg_line_info_ = std::move(dbg_line_info);
285   }
286 
trailing_dbg_line_info()287   std::vector<Instruction>& trailing_dbg_line_info() {
288     return trailing_dbg_line_info_;
289   }
290 
trailing_dbg_line_info()291   const std::vector<Instruction>& trailing_dbg_line_info() const {
292     return trailing_dbg_line_info_;
293   }
294 
295  private:
296   ModuleHeader header_;  // Module header
297 
298   // The following fields respect the "Logical Layout of a Module" in
299   // Section 2.4 of the SPIR-V specification.
300   IRContext* context_;
301   InstructionList capabilities_;
302   InstructionList extensions_;
303   InstructionList ext_inst_imports_;
304   // A module only has one memory model instruction.
305   std::unique_ptr<Instruction> memory_model_;
306   // A module can only have one optional sampled image addressing mode
307   std::unique_ptr<Instruction> sampled_image_address_mode_;
308   InstructionList entry_points_;
309   InstructionList execution_modes_;
310   InstructionList debugs1_;
311   InstructionList debugs2_;
312   InstructionList debugs3_;
313   InstructionList ext_inst_debuginfo_;
314   InstructionList annotations_;
315   // Type declarations, constants, and global variable declarations.
316   InstructionList types_values_;
317   std::vector<std::unique_ptr<Function>> functions_;
318 
319   // If the module ends with Op*Line instruction, they will not be attached to
320   // any instruction.  We record them here, so they will not be lost.
321   std::vector<Instruction> trailing_dbg_line_info_;
322 
323   // This module contains DebugScope/DebugNoScope or OpLine/OpNoLine.
324   bool contains_debug_info_;
325 };
326 
327 // Pretty-prints |module| to |str|. Returns |str|.
328 std::ostream& operator<<(std::ostream& str, const Module& module);
329 
AddCapability(std::unique_ptr<Instruction> c)330 inline void Module::AddCapability(std::unique_ptr<Instruction> c) {
331   capabilities_.push_back(std::move(c));
332 }
333 
AddExtension(std::unique_ptr<Instruction> e)334 inline void Module::AddExtension(std::unique_ptr<Instruction> e) {
335   extensions_.push_back(std::move(e));
336 }
337 
AddExtInstImport(std::unique_ptr<Instruction> e)338 inline void Module::AddExtInstImport(std::unique_ptr<Instruction> e) {
339   ext_inst_imports_.push_back(std::move(e));
340 }
341 
SetMemoryModel(std::unique_ptr<Instruction> m)342 inline void Module::SetMemoryModel(std::unique_ptr<Instruction> m) {
343   memory_model_ = std::move(m);
344 }
345 
SetSampledImageAddressMode(std::unique_ptr<Instruction> m)346 inline void Module::SetSampledImageAddressMode(std::unique_ptr<Instruction> m) {
347   sampled_image_address_mode_ = std::move(m);
348 }
349 
AddEntryPoint(std::unique_ptr<Instruction> e)350 inline void Module::AddEntryPoint(std::unique_ptr<Instruction> e) {
351   entry_points_.push_back(std::move(e));
352 }
353 
AddExecutionMode(std::unique_ptr<Instruction> e)354 inline void Module::AddExecutionMode(std::unique_ptr<Instruction> e) {
355   execution_modes_.push_back(std::move(e));
356 }
357 
AddDebug1Inst(std::unique_ptr<Instruction> d)358 inline void Module::AddDebug1Inst(std::unique_ptr<Instruction> d) {
359   debugs1_.push_back(std::move(d));
360 }
361 
AddDebug2Inst(std::unique_ptr<Instruction> d)362 inline void Module::AddDebug2Inst(std::unique_ptr<Instruction> d) {
363   debugs2_.push_back(std::move(d));
364 }
365 
AddDebug3Inst(std::unique_ptr<Instruction> d)366 inline void Module::AddDebug3Inst(std::unique_ptr<Instruction> d) {
367   debugs3_.push_back(std::move(d));
368 }
369 
AddExtInstDebugInfo(std::unique_ptr<Instruction> d)370 inline void Module::AddExtInstDebugInfo(std::unique_ptr<Instruction> d) {
371   ext_inst_debuginfo_.push_back(std::move(d));
372 }
373 
AddAnnotationInst(std::unique_ptr<Instruction> a)374 inline void Module::AddAnnotationInst(std::unique_ptr<Instruction> a) {
375   annotations_.push_back(std::move(a));
376 }
377 
AddType(std::unique_ptr<Instruction> t)378 inline void Module::AddType(std::unique_ptr<Instruction> t) {
379   types_values_.push_back(std::move(t));
380 }
381 
AddGlobalValue(std::unique_ptr<Instruction> v)382 inline void Module::AddGlobalValue(std::unique_ptr<Instruction> v) {
383   types_values_.push_back(std::move(v));
384 }
385 
AddFunctionDeclaration(std::unique_ptr<Function> f)386 inline void Module::AddFunctionDeclaration(std::unique_ptr<Function> f) {
387   // function declarations must come before function definitions.
388   functions_.emplace(functions_.begin(), std::move(f));
389 }
390 
AddFunction(std::unique_ptr<Function> f)391 inline void Module::AddFunction(std::unique_ptr<Function> f) {
392   functions_.emplace_back(std::move(f));
393 }
394 
SetContainsDebugInfo()395 inline void Module::SetContainsDebugInfo() { contains_debug_info_ = true; }
396 
capability_begin()397 inline Module::inst_iterator Module::capability_begin() {
398   return capabilities_.begin();
399 }
capability_end()400 inline Module::inst_iterator Module::capability_end() {
401   return capabilities_.end();
402 }
403 
capabilities()404 inline IteratorRange<Module::inst_iterator> Module::capabilities() {
405   return make_range(capabilities_.begin(), capabilities_.end());
406 }
407 
capabilities()408 inline IteratorRange<Module::const_inst_iterator> Module::capabilities() const {
409   return make_range(capabilities_.begin(), capabilities_.end());
410 }
411 
ext_inst_import_begin()412 inline Module::inst_iterator Module::ext_inst_import_begin() {
413   return ext_inst_imports_.begin();
414 }
ext_inst_import_end()415 inline Module::inst_iterator Module::ext_inst_import_end() {
416   return ext_inst_imports_.end();
417 }
418 
ext_inst_imports()419 inline IteratorRange<Module::inst_iterator> Module::ext_inst_imports() {
420   return make_range(ext_inst_imports_.begin(), ext_inst_imports_.end());
421 }
422 
ext_inst_imports()423 inline IteratorRange<Module::const_inst_iterator> Module::ext_inst_imports()
424     const {
425   return make_range(ext_inst_imports_.begin(), ext_inst_imports_.end());
426 }
427 
debug1_begin()428 inline Module::inst_iterator Module::debug1_begin() { return debugs1_.begin(); }
debug1_end()429 inline Module::inst_iterator Module::debug1_end() { return debugs1_.end(); }
430 
debugs1()431 inline IteratorRange<Module::inst_iterator> Module::debugs1() {
432   return make_range(debugs1_.begin(), debugs1_.end());
433 }
434 
debugs1()435 inline IteratorRange<Module::const_inst_iterator> Module::debugs1() const {
436   return make_range(debugs1_.begin(), debugs1_.end());
437 }
438 
debug2_begin()439 inline Module::inst_iterator Module::debug2_begin() { return debugs2_.begin(); }
debug2_end()440 inline Module::inst_iterator Module::debug2_end() { return debugs2_.end(); }
441 
debugs2()442 inline IteratorRange<Module::inst_iterator> Module::debugs2() {
443   return make_range(debugs2_.begin(), debugs2_.end());
444 }
445 
debugs2()446 inline IteratorRange<Module::const_inst_iterator> Module::debugs2() const {
447   return make_range(debugs2_.begin(), debugs2_.end());
448 }
449 
debug3_begin()450 inline Module::inst_iterator Module::debug3_begin() { return debugs3_.begin(); }
debug3_end()451 inline Module::inst_iterator Module::debug3_end() { return debugs3_.end(); }
452 
debugs3()453 inline IteratorRange<Module::inst_iterator> Module::debugs3() {
454   return make_range(debugs3_.begin(), debugs3_.end());
455 }
456 
debugs3()457 inline IteratorRange<Module::const_inst_iterator> Module::debugs3() const {
458   return make_range(debugs3_.begin(), debugs3_.end());
459 }
460 
ext_inst_debuginfo_begin()461 inline Module::inst_iterator Module::ext_inst_debuginfo_begin() {
462   return ext_inst_debuginfo_.begin();
463 }
ext_inst_debuginfo_end()464 inline Module::inst_iterator Module::ext_inst_debuginfo_end() {
465   return ext_inst_debuginfo_.end();
466 }
467 
ext_inst_debuginfo()468 inline IteratorRange<Module::inst_iterator> Module::ext_inst_debuginfo() {
469   return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end());
470 }
471 
ext_inst_debuginfo()472 inline IteratorRange<Module::const_inst_iterator> Module::ext_inst_debuginfo()
473     const {
474   return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end());
475 }
476 
entry_points()477 inline IteratorRange<Module::inst_iterator> Module::entry_points() {
478   return make_range(entry_points_.begin(), entry_points_.end());
479 }
480 
entry_points()481 inline IteratorRange<Module::const_inst_iterator> Module::entry_points() const {
482   return make_range(entry_points_.begin(), entry_points_.end());
483 }
484 
execution_mode_begin()485 inline Module::inst_iterator Module::execution_mode_begin() {
486   return execution_modes_.begin();
487 }
execution_mode_end()488 inline Module::inst_iterator Module::execution_mode_end() {
489   return execution_modes_.end();
490 }
491 
execution_modes()492 inline IteratorRange<Module::inst_iterator> Module::execution_modes() {
493   return make_range(execution_modes_.begin(), execution_modes_.end());
494 }
495 
execution_modes()496 inline IteratorRange<Module::const_inst_iterator> Module::execution_modes()
497     const {
498   return make_range(execution_modes_.begin(), execution_modes_.end());
499 }
500 
annotation_begin()501 inline Module::inst_iterator Module::annotation_begin() {
502   return annotations_.begin();
503 }
annotation_end()504 inline Module::inst_iterator Module::annotation_end() {
505   return annotations_.end();
506 }
507 
annotations()508 inline IteratorRange<Module::inst_iterator> Module::annotations() {
509   return make_range(annotations_.begin(), annotations_.end());
510 }
511 
annotations()512 inline IteratorRange<Module::const_inst_iterator> Module::annotations() const {
513   return make_range(annotations_.begin(), annotations_.end());
514 }
515 
extension_begin()516 inline Module::inst_iterator Module::extension_begin() {
517   return extensions_.begin();
518 }
extension_end()519 inline Module::inst_iterator Module::extension_end() {
520   return extensions_.end();
521 }
522 
extensions()523 inline IteratorRange<Module::inst_iterator> Module::extensions() {
524   return make_range(extensions_.begin(), extensions_.end());
525 }
526 
extensions()527 inline IteratorRange<Module::const_inst_iterator> Module::extensions() const {
528   return make_range(extensions_.begin(), extensions_.end());
529 }
530 
types_values_begin()531 inline Module::inst_iterator Module::types_values_begin() {
532   return types_values_.begin();
533 }
534 
types_values_end()535 inline Module::inst_iterator Module::types_values_end() {
536   return types_values_.end();
537 }
538 
types_values()539 inline IteratorRange<Module::inst_iterator> Module::types_values() {
540   return make_range(types_values_.begin(), types_values_.end());
541 }
542 
types_values()543 inline IteratorRange<Module::const_inst_iterator> Module::types_values() const {
544   return make_range(types_values_.begin(), types_values_.end());
545 }
546 
cbegin()547 inline Module::const_iterator Module::cbegin() const {
548   return const_iterator(&functions_, functions_.cbegin());
549 }
550 
cend()551 inline Module::const_iterator Module::cend() const {
552   return const_iterator(&functions_, functions_.cend());
553 }
554 
555 }  // namespace opt
556 }  // namespace spvtools
557 
558 #endif  // SOURCE_OPT_MODULE_H_
559