Skip to content

Commit 34c98fa

Browse files
Wrappers for MemoryBuffer (#35)
* Added wrapper for `MemoryBuffer` and added the memory buffer producing files to `TargetMachine` * Added `start` and `size` properties. * Updated doc comment * 4-spaces to 2-spaces
1 parent 20ec52f commit 34c98fa

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

Sources/LLVM/MemoryBuffer.swift

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import cllvm
2+
3+
/// Enumerates the possible failures that can be thrown initializing
4+
/// a MemoryBuffer.
5+
public enum MemoryBufferError: Error {
6+
/// The MemoryBuffer failed to be initialized for a specific reason.
7+
case couldNotCreate(String)
8+
}
9+
10+
/// `MemoryBuffer` provides simple read-only access to a block of memory, and
11+
/// provides simple methods for reading files and standard input into a memory
12+
/// buffer. In addition to basic access to the characters in the file, this
13+
/// interface guarantees you can read one character past the end of the file,
14+
/// and that this character will read as '\0'.
15+
///
16+
/// The '\0' guarantee is needed to support an optimization -- it's intended to
17+
/// be more efficient for clients which are reading all the data to stop
18+
/// reading when they encounter a '\0' than to continually check the file
19+
/// position to see if it has reached the end of the file.
20+
public class MemoryBuffer: Sequence {
21+
let llvm: LLVMMemoryBufferRef
22+
23+
/// Creates a `MemoryBuffer` with the contents of `stdin`, stopping once
24+
/// `EOF` is read.
25+
/// - throws: `MemoryBufferError` if there was an error on creation.
26+
public static func fromStdin() throws -> MemoryBuffer {
27+
var buf: LLVMMemoryBufferRef?
28+
var error: UnsafeMutablePointer<Int8>?
29+
LLVMCreateMemoryBufferWithSTDIN(&buf, &error)
30+
if let error = error {
31+
defer { LLVMDisposeMessage(error) }
32+
throw MemoryBufferError.couldNotCreate(String(cString: error))
33+
}
34+
guard let llvm = buf else {
35+
throw MemoryBufferError.couldNotCreate("unknown reason")
36+
}
37+
return MemoryBuffer(llvm: llvm)
38+
}
39+
40+
41+
/// Creates a MemoryBuffer from the underlying `LLVMMemoryBufferRef`
42+
///
43+
/// - parameter llvm: The LLVMMemoryBufferRef with which to initialize
44+
internal init(llvm: LLVMMemoryBufferRef) {
45+
self.llvm = llvm
46+
}
47+
48+
/// Creates a `MemoryBuffer` that points to a specified
49+
/// `UnsafeBufferPointer`.
50+
///
51+
/// - parameters:
52+
/// - buffer: The underlying buffer that contains the data.
53+
/// - name: The name for the new memory buffer.
54+
/// - requiresNullTerminator: Whether or not the `MemoryBuffer` should
55+
/// append a null terminator. Defaults to
56+
/// `false`
57+
public init(buffer: UnsafeBufferPointer<Int8>,
58+
name: String,
59+
requiresNullTerminator: Bool = false) {
60+
llvm = LLVMCreateMemoryBufferWithMemoryRange(buffer.baseAddress,
61+
buffer.count,
62+
name,
63+
requiresNullTerminator.llvm)
64+
}
65+
66+
/// Creates a `MemoryBuffer` by copying the data within a specified
67+
/// `UnsafeBufferPointer`.
68+
///
69+
/// - parameters:
70+
/// - buffer: The underlying buffer that contains the data.
71+
/// - name: The name for the new memory buffer.
72+
public init(copyingBuffer buffer: UnsafeBufferPointer<Int8>,
73+
name: String) {
74+
llvm = LLVMCreateMemoryBufferWithMemoryRangeCopy(buffer.baseAddress,
75+
buffer.count,
76+
name)
77+
}
78+
79+
80+
/// Creates a `MemoryBuffer` with the contents of the file at the provided
81+
/// path.
82+
///
83+
/// - parameter file: The full path of the file you're trying to read.
84+
/// - throws: `MemoryBufferError` if there was a problem creating
85+
/// the buffer or reading the file.
86+
public init(contentsOf file: String) throws {
87+
var buf: LLVMMemoryBufferRef?
88+
var error: UnsafeMutablePointer<Int8>?
89+
LLVMCreateMemoryBufferWithContentsOfFile(file, &buf, &error)
90+
if let error = error {
91+
defer { LLVMDisposeMessage(error) }
92+
throw MemoryBufferError.couldNotCreate(String(cString: error))
93+
}
94+
guard let llvm = buf else {
95+
throw MemoryBufferError.couldNotCreate("unknown reason")
96+
}
97+
self.llvm = llvm
98+
}
99+
100+
/// Retrieves the start address of this buffer.
101+
public var start: UnsafePointer<Int8> {
102+
return LLVMGetBufferStart(llvm)
103+
}
104+
105+
/// Retrieves the size in bytes of this buffer.
106+
public var size: Int {
107+
return LLVMGetBufferSize(llvm)
108+
}
109+
110+
/// Makes an iterator so this buffer can be traversed in a `for` loop.
111+
public func makeIterator() -> UnsafeBufferPointerIterator<Int8> {
112+
return UnsafeBufferPointer(start: start, count: size).makeIterator()
113+
}
114+
115+
deinit {
116+
LLVMDisposeMemoryBuffer(llvm)
117+
}
118+
}

Sources/LLVM/TargetMachine.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,36 @@ public class TargetMachine {
162162
}
163163
}
164164

165+
/// Emits an LLVM Bitcode, ASM, or object file for the given module to a new
166+
/// `MemoryBuffer` containing the contents.
167+
///
168+
/// Failure during any part of the compilation process or the process of
169+
/// writing the results to disk will result in a `TargetMachineError` being
170+
/// thrown describing the error in detail.
171+
///
172+
/// - parameter module: The module whose contents will be codegened.
173+
/// - parameter type: The type of codegen to perform on the given module.
174+
public func emitToMemoryBuffer(module: Module, type: CodegenFileType) throws -> MemoryBuffer {
175+
if case .bitCode = type {
176+
guard let buffer = LLVMWriteBitcodeToMemoryBuffer(module.llvm) else {
177+
throw TargetMachineError.couldNotEmitBitCode
178+
}
179+
return MemoryBuffer(llvm: buffer)
180+
}
181+
var buf: LLVMMemoryBufferRef?
182+
var error: UnsafeMutablePointer<Int8>?
183+
LLVMTargetMachineEmitToMemoryBuffer(llvm, module.llvm,
184+
type.asLLVM(), &error, &buf)
185+
if let error = error {
186+
defer { free(error) }
187+
throw TargetMachineError.couldNotEmit(String(cString: error), type)
188+
}
189+
guard let llvm = buf else {
190+
throw TargetMachineError.couldNotEmit("unknown reason", type)
191+
}
192+
return MemoryBuffer(llvm: llvm)
193+
}
194+
165195
deinit {
166196
LLVMDisposeTargetMachine(llvm)
167197
}

0 commit comments

Comments
 (0)