2 * Copyright 2017 Jacob Lifshay
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 #include <type_traits>
30 #include "spirv/spirv.h"
31 #include "spirv/parser.h"
32 #include "util/optional.h"
33 #include "util/string_view.h"
34 #include "spirv_to_llvm/spirv_to_llvm.h"
35 #include "llvm_wrapper/llvm_wrapper.h"
41 util::optional
<std::vector
<spirv::Word
>> load_file(const char *filename
)
44 constexpr int eof
= std::char_traits
<char>::eof();
46 is
.open(filename
, std::ios::in
| std::ios::binary
);
49 constexpr std::size_t block_size
= 0x1000;
50 std::vector
<std::array
<Word
, block_size
>> blocks
;
51 std::array
<unsigned char, sizeof(Word
)> word_bytes
{};
52 static_assert(sizeof(Word
) == 4, "");
53 static_assert(std::is_same
<std::uint8_t, unsigned char>::value
, "");
54 auto read_little_endian
= [](const unsigned char *bytes
) -> Word
56 Word retval
= bytes
[3];
65 auto read_big_endian
= [](const unsigned char *bytes
) -> Word
67 Word retval
= bytes
[0];
76 for(unsigned char &byte
: word_bytes
)
83 Word (*read_word_fn
)(const unsigned char *) = nullptr;
84 if(read_little_endian(word_bytes
.data()) == spirv::magic_number
)
85 read_word_fn
= read_little_endian
;
86 else if(read_big_endian(word_bytes
.data()) == spirv::magic_number
)
87 read_word_fn
= read_big_endian
;
90 std::size_t word_count
= 1;
91 blocks
.emplace_back();
92 blocks
[0][0] = read_word_fn(word_bytes
.data());
93 std::size_t word_in_block_index
= 1;
94 while(is
.peek() != eof
)
96 for(unsigned char &byte
: word_bytes
)
103 blocks
.back()[word_in_block_index
++] = read_word_fn(word_bytes
.data());
105 if(word_in_block_index
>= block_size
)
107 word_in_block_index
= 0;
108 blocks
.emplace_back();
111 std::vector
<Word
> retval
;
112 retval
.reserve(word_count
);
113 word_in_block_index
= 0;
114 for(std::size_t word_index
= 0, block_index
= 0; word_index
< word_count
; word_index
++)
116 retval
.push_back(blocks
[block_index
][word_in_block_index
++]);
117 if(word_in_block_index
>= block_size
)
119 word_in_block_index
= 0;
123 return std::move(retval
);
126 void dump_words(const spirv::Word
*words
, std::size_t word_count
)
128 constexpr std::size_t max_words_per_line
= 4;
129 auto old_fill
= std::cerr
.fill('0');
130 auto old_flags
= std::cerr
.flags(std::ios::uppercase
| std::ios::hex
| std::ios::right
);
131 auto old_width
= std::cerr
.width();
132 bool wrote_line_beginning
= false;
133 bool wrote_line_ending
= true;
134 std::cerr
<< "Words:\n";
135 std::size_t current_words_per_line
= 0;
138 auto write_line_beginning
= [&]()
141 std::cerr
<< index
<< ":";
143 wrote_line_beginning
= true;
144 wrote_line_ending
= false;
146 std::string chars
= "";
147 auto write_line_ending
= [&]()
149 while(current_words_per_line
< max_words_per_line
)
151 std::cerr
<< seperator
;
157 current_words_per_line
++;
159 std::cerr
<< seperator
<< " |" << chars
<< "|\n";
161 wrote_line_ending
= true;
162 wrote_line_beginning
= false;
163 current_words_per_line
= 0;
166 auto append_char
= [&](unsigned ch
)
168 if(ch
>= 0x20U
&& ch
< 0x7FU
)
169 chars
+= static_cast<char>(ch
);
173 auto write_word
= [&](spirv::Word w
)
175 std::cerr
<< seperator
;
179 current_words_per_line
++;
180 append_char(w
& 0xFFU
);
181 append_char((w
>> 8) & 0xFFU
);
182 append_char((w
>> 16) & 0xFFU
);
183 append_char((w
>> 24) & 0xFFU
);
185 for(index
= 0; index
< word_count
; index
++)
187 if(current_words_per_line
>= max_words_per_line
)
189 if(!wrote_line_beginning
)
190 write_line_beginning();
191 write_word(words
[index
]);
193 if(!wrote_line_ending
)
196 std::cerr
.width(old_width
);
197 std::cerr
.fill(old_fill
);
198 std::cerr
.flags(old_flags
);
201 void dump_words(const std::vector
<spirv::Word
> &words
)
203 dump_words(words
.data(), words
.size());
206 int test_main(int argc
, char **argv
)
208 const char *filename
= "test-files/test.spv";
211 if(argv
[1][0] == '-')
213 std::cerr
<< "usage: demo [<file.spv>]\n";
218 std::cerr
<< "loading " << filename
<< std::endl
;
219 auto file
= load_file(filename
);
224 std::cerr
<< std::endl
;
225 spirv::Dump_callbacks dump_callbacks
;
228 spirv::parse(dump_callbacks
, file
->data(), file
->size());
230 catch(spirv::Parser_error
&e
)
232 std::cerr
<< dump_callbacks
.ss
.str() << std::endl
;
233 std::cerr
<< "error: " << e
.what();
236 std::cerr
<< dump_callbacks
.ss
.str() << std::endl
;
238 auto llvm_target_machine
= llvm_wrapper::Target_machine::create_native_target_machine();
239 auto llvm_context
= llvm_wrapper::Context::create();
240 std::uint64_t next_module_id
= 1;
241 spirv_to_llvm::Converted_module converted_module
;
244 converted_module
= spirv_to_llvm::spirv_to_llvm(llvm_context
.get(),
245 llvm_target_machine
.get(),
249 spirv::Execution_model::vertex
,
252 catch(spirv::Parser_error
&e
)
254 std::cerr
<< "error: " << e
.what();
257 std::cerr
<< "Translation to LLVM succeeded." << std::endl
;
258 ::LLVMDumpModule(converted_module
.module
.get());
260 ::LLVMVerifyModule(converted_module
.module
.get(), ::LLVMPrintMessageAction
, nullptr);
263 auto orc_jit_stack
= llvm_wrapper::Orc_jit_stack::create(std::move(llvm_target_machine
));
264 orc_jit_stack
.add_eagerly_compiled_ir(
265 std::move(converted_module
.module
),
266 [](const char *symbol_name
, [[gnu::unused
]] void *user_data
) noexcept
->std::uint64_t
268 std::cerr
<< "resolving symbol: " << symbol_name
<< std::endl
;
269 void *symbol
= nullptr;
270 return reinterpret_cast<std::uintptr_t>(symbol
);
273 auto function
= reinterpret_cast<void *>(
274 orc_jit_stack
.get_symbol_address(converted_module
.entry_function_name
.c_str()));
275 std::cerr
<< "entry point: " << converted_module
.entry_function_name
<< ": " << function
280 std::cerr
<< "error: can't load file" << std::endl
;
288 int main(int argc
, char **argv
)
290 return vulkan_cpu::test::test_main(argc
, argv
);