SPIRV-Tools/source/opt/ir_loader.h
Jaebaek Seo 56d0f50357
Propagate OpLine to all applied instructions in spirv-opt (#3951)
Based on the OpLine spec, an OpLine instruction must be applied to
the instructions physically following it up to the first occurrence
of the next end of block, the next OpLine instruction, or the next
OpNoLine instruction.

```
OpLine %file 0 0
OpNoLine
OpLine %file 1 1
OpStore %foo %int_1
%value = OpLoad %int %foo
OpLine %file 2 2
```

For the above code, the current spirv-opt keeps three line
instructions `OpLine %file 0 0`, `OpNoLine`, and `OpLine %file 1 1`
in `std::vector<Instruction> dbg_line_insts_` of Instruction class
for `OpStore %foo %int_1`. It does not put any line instruction to
`std::vector<Instruction> dbg_line_insts_` of
`%value = OpLoad %int %foo` even though `OpLine %file 1 1` must be
applied to `%value = OpLoad %int %foo` based on the spec.

This results in the missing line information for
`%value = OpLoad %int %foo` while each spirv-opt pass optimizes the
code. We have to put `OpLine %file 1 1` to
`std::vector<Instruction> dbg_line_insts_` of
both `%value = OpLoad %int %foo` and `OpStore %foo %int_1`.

This commit conducts the line instruction propagation and skips
emitting the eliminated line instructions at the end, which are the same
with PropagateLineInfoPass and RedundantLineInfoElimPass. This
commit removes PropagateLineInfoPass and RedundantLineInfoElimPass.

KhronosGroup/glslang#2440 is a related PR that stop using
PropagateLineInfoPass and RedundantLineInfoElimPass from glslang.
When the code in this PR applied, the glslang tests will pass.
2020-10-29 13:06:30 -04:00

92 lines
3.6 KiB
C++

// Copyright (c) 2016 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.
#ifndef SOURCE_OPT_IR_LOADER_H_
#define SOURCE_OPT_IR_LOADER_H_
#include <memory>
#include <string>
#include <vector>
#include "source/opt/basic_block.h"
#include "source/opt/instruction.h"
#include "source/opt/module.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
namespace opt {
// Loader class for constructing SPIR-V in-memory IR representation. Methods in
// this class are designed to work with the interface for spvBinaryParse() in
// libspirv.h so that we can leverage the syntax checks implemented behind it.
//
// The user is expected to call SetModuleHeader() to fill in the module's
// header, and then AddInstruction() for each decoded instruction, and finally
// EndModule() to finalize the module. The instructions processed in sequence
// by AddInstruction() should comprise a valid SPIR-V module.
class IrLoader {
public:
// Instantiates a builder to construct the given |module| gradually.
// All internal messages will be communicated to the outside via the given
// message |consumer|. This instance only keeps a reference to the |consumer|,
// so the |consumer| should outlive this instance.
IrLoader(const MessageConsumer& consumer, Module* m);
// Sets the source name of the module.
void SetSource(const std::string& src) { source_ = src; }
Module* module() const { return module_; }
// Sets the fields in the module's header to the given parameters.
void SetModuleHeader(uint32_t magic, uint32_t version, uint32_t generator,
uint32_t bound, uint32_t reserved) {
module_->SetHeader({magic, version, generator, bound, reserved});
}
// Adds an instruction to the module. Returns true if no error occurs. This
// method will properly capture and store the data provided in |inst| so that
// |inst| is no longer needed after returning.
bool AddInstruction(const spv_parsed_instruction_t* inst);
// Finalizes the module construction. This must be called after the module
// header has been set and all instructions have been added. This is
// forgiving in the case of a missing terminator instruction on a basic block,
// or a missing OpFunctionEnd. Resolves internal bookkeeping.
void EndModule();
private:
// Consumer for communicating messages to outside.
const MessageConsumer& consumer_;
// The module to be built.
Module* module_;
// The source name of the module.
std::string source_;
// The last used instruction index.
uint32_t inst_index_;
// The current Function under construction.
std::unique_ptr<Function> function_;
// The current BasicBlock under construction.
std::unique_ptr<BasicBlock> block_;
// Line related debug instructions accumulated thus far.
std::vector<Instruction> dbg_line_info_;
// Line instruction that should be applied to the next instruction.
std::unique_ptr<Instruction> last_line_inst_;
// The last DebugScope information that IrLoader::AddInstruction() handled.
DebugScope last_dbg_scope_;
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_IR_LOADER_H_