1 // Copyright 2020 The Tint Authors.
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 #include "src/writer/spirv/binary_writer.h"
16 
17 #include <cstring>
18 
19 namespace tint {
20 namespace writer {
21 namespace spirv {
22 namespace {
23 
24 const uint32_t kGeneratorId = 23u << 16;
25 
26 }  // namespace
27 
28 BinaryWriter::BinaryWriter() = default;
29 
30 BinaryWriter::~BinaryWriter() = default;
31 
WriteBuilder(Builder * builder)32 void BinaryWriter::WriteBuilder(Builder* builder) {
33   out_.reserve(builder->total_size());
34   builder->iterate(
35       [this](const Instruction& inst) { this->process_instruction(inst); });
36 }
37 
WriteInstruction(const Instruction & inst)38 void BinaryWriter::WriteInstruction(const Instruction& inst) {
39   process_instruction(inst);
40 }
41 
WriteHeader(uint32_t bound)42 void BinaryWriter::WriteHeader(uint32_t bound) {
43   out_.push_back(spv::MagicNumber);
44   out_.push_back(0x00010300);  // Version 1.3
45   out_.push_back(kGeneratorId);
46   out_.push_back(bound);
47   out_.push_back(0);
48 }
49 
process_instruction(const Instruction & inst)50 void BinaryWriter::process_instruction(const Instruction& inst) {
51   out_.push_back(inst.word_length() << 16 |
52                  static_cast<uint32_t>(inst.opcode()));
53   for (const auto& op : inst.operands()) {
54     process_op(op);
55   }
56 }
57 
process_op(const Operand & op)58 void BinaryWriter::process_op(const Operand& op) {
59   if (op.IsFloat()) {
60     // Allocate space for the float
61     out_.push_back(0);
62     auto f = op.to_f();
63     uint8_t* ptr = reinterpret_cast<uint8_t*>(out_.data() + (out_.size() - 1));
64     memcpy(ptr, &f, 4);
65   } else if (op.IsInt()) {
66     out_.push_back(op.to_i());
67   } else {
68     auto idx = out_.size();
69     const auto& str = op.to_s();
70     out_.resize(out_.size() + op.length(), 0);
71     memcpy(out_.data() + idx, str.c_str(), str.size() + 1);
72   }
73 }
74 
75 }  // namespace spirv
76 }  // namespace writer
77 }  // namespace tint
78