1 /** 2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This file contains convenient functionality for reading/writing LLVM bitcode 7 and IR. 8 The functions prefer using D's stdlib for IO when possible. 9 */ 10 module llvm_hiwrap.io; 11 12 import std.stdio : File; 13 import llvm_hiwrap.module_ : Module; 14 import llvm_hiwrap.context : Context; 15 16 /** Write a LLVM module to the file. 17 * 18 * The function seems silly. It is mostly for self documenting purpose. 19 * 20 * NOTE: The file extension should be ".bc". 21 * NOTE: I have confirmed that this function produces the same output as if 22 * LLVMWriteBitcodeToFile is called. See the unittests further down. 23 */ 24 void writeModule(File f, ref Module m) { 25 auto buf = m.toBuffer; 26 f.rawWrite(buf.slice); 27 } 28 29 @("shall be a dump of the module to a file") 30 unittest { 31 import std.file : remove; 32 33 immutable p = "remove_me_module_dump_phobos.bc"; 34 scope (exit) 35 remove(p); 36 37 auto m = Module("as_file"); 38 auto f = File(p, "w"); 39 f.writeModule(m); 40 } 41 42 @("shall be no difference between LLVM IO and when using phobos") 43 unittest { 44 import std.file; 45 import llvm_hiwrap.llvm_io; 46 47 // arrange 48 immutable llvm_io_output = "remove_me_llmv_io_output.bc"; 49 immutable hiwrap_io_output = "remove_me_hiwrap_io_output.bc"; 50 auto test_module = Module("test"); 51 52 // act 53 test_module.dumpToFile(llvm_io_output); 54 scope (exit) 55 remove(llvm_io_output); 56 57 File(hiwrap_io_output, "w").writeModule(test_module); 58 scope (exit) 59 remove(hiwrap_io_output); 60 61 // assert 62 ubyte[] llvm_io_data = cast(ubyte[]) std.file.read(llvm_io_output); 63 ubyte[] hiwrap_io_data = cast(ubyte[]) std.file.read(hiwrap_io_output); 64 65 assert(llvm_io_data == hiwrap_io_data); 66 } 67 68 /** Read a LLVM module from the file. 69 * 70 */ 71 auto readModule(File f, ref Context ctx, string module_id = null) { 72 import llvm_hiwrap.buffer; 73 74 ubyte[1024] buf; 75 ubyte[] raw_data; 76 raw_data.reserve(1024); 77 78 { 79 ubyte[] read_bytes; 80 do { 81 read_bytes = f.rawRead(buf); 82 raw_data ~= read_bytes; 83 } 84 while (read_bytes.length != 0); 85 } 86 87 auto llvm_buf = MemoryBuffer.fromMemory(raw_data, module_id); 88 89 return ctx.makeModule(llvm_buf); 90 } 91 92 @("the written file shall be equivalent to the original when read back (serialize/deserialize)") 93 unittest { 94 import std.file; 95 import llvm_hiwrap.context; 96 import test_utils; 97 98 // arrange 99 auto ctx = Context.make; 100 auto test_module = ctx.makeModule("foo"); 101 102 immutable test_module_output = "remove_me_test_module_file.bc"; 103 File(test_module_output, "w").writeModule(test_module); 104 scope (exit) 105 remove(test_module_output); 106 107 // act 108 auto read_module = File(test_module_output).readModule(ctx, "foo"); 109 110 // assert 111 assert(read_module.isValid); 112 113 auto extracted_read_module = read_module.value; 114 115 auto original_as_txt = test_module.toString; 116 auto read_as_txt = extracted_read_module.toString; 117 118 assert(original_as_txt == read_as_txt); 119 }