Skip to content

Wrappers for MemoryBuffer #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions Sources/LLVM/MemoryBuffer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import cllvm

/// Enumerates the possible failures that can be thrown initializing
/// a MemoryBuffer.
public enum MemoryBufferError: Error {
/// The MemoryBuffer failed to be initialized for a specific reason.
case couldNotCreate(String)
}

/// `MemoryBuffer` provides simple read-only access to a block of memory, and
/// provides simple methods for reading files and standard input into a memory
/// buffer. In addition to basic access to the characters in the file, this
/// interface guarantees you can read one character past the end of the file,
/// and that this character will read as '\0'.
///
/// The '\0' guarantee is needed to support an optimization -- it's intended to
/// be more efficient for clients which are reading all the data to stop
/// reading when they encounter a '\0' than to continually check the file
/// position to see if it has reached the end of the file.
public class MemoryBuffer: Sequence {
let llvm: LLVMMemoryBufferRef

/// Creates a `MemoryBuffer` with the contents of `stdin`, stopping once
/// `EOF` is read.
/// - throws: `MemoryBufferError` if there was an error on creation.
public static func fromStdin() throws -> MemoryBuffer {
var buf: LLVMMemoryBufferRef?
var error: UnsafeMutablePointer<Int8>?
LLVMCreateMemoryBufferWithSTDIN(&buf, &error)
if let error = error {
defer { LLVMDisposeMessage(error) }
throw MemoryBufferError.couldNotCreate(String(cString: error))
}
guard let llvm = buf else {
throw MemoryBufferError.couldNotCreate("unknown reason")
}
return MemoryBuffer(llvm: llvm)
}


/// Creates a MemoryBuffer from the underlying `LLVMMemoryBufferRef`
///
/// - parameter llvm: The LLVMMemoryBufferRef with which to initialize
internal init(llvm: LLVMMemoryBufferRef) {
self.llvm = llvm
}

/// Creates a `MemoryBuffer` that points to a specified
/// `UnsafeBufferPointer`.
///
/// - parameters:
/// - buffer: The underlying buffer that contains the data.
/// - name: The name for the new memory buffer.
/// - requiresNullTerminator: Whether or not the `MemoryBuffer` should
/// append a null terminator. Defaults to
/// `false`
public init(buffer: UnsafeBufferPointer<Int8>,
name: String,
requiresNullTerminator: Bool = false) {
llvm = LLVMCreateMemoryBufferWithMemoryRange(buffer.baseAddress,
buffer.count,
name,
requiresNullTerminator.llvm)
}

/// Creates a `MemoryBuffer` by copying the data within a specified
/// `UnsafeBufferPointer`.
///
/// - parameters:
/// - buffer: The underlying buffer that contains the data.
/// - name: The name for the new memory buffer.
public init(copyingBuffer buffer: UnsafeBufferPointer<Int8>,
name: String) {
llvm = LLVMCreateMemoryBufferWithMemoryRangeCopy(buffer.baseAddress,
buffer.count,
name)
}


/// Creates a `MemoryBuffer` with the contents of the file at the provided
/// path.
///
/// - parameter file: The full path of the file you're trying to read.
/// - throws: `MemoryBufferError` if there was a problem creating
/// the buffer or reading the file.
public init(contentsOf file: String) throws {
var buf: LLVMMemoryBufferRef?
var error: UnsafeMutablePointer<Int8>?
LLVMCreateMemoryBufferWithContentsOfFile(file, &buf, &error)
if let error = error {
defer { LLVMDisposeMessage(error) }
throw MemoryBufferError.couldNotCreate(String(cString: error))
}
guard let llvm = buf else {
throw MemoryBufferError.couldNotCreate("unknown reason")
}
self.llvm = llvm
}

/// Retrieves the start address of this buffer.
public var start: UnsafePointer<Int8> {
return LLVMGetBufferStart(llvm)
}

/// Retrieves the size in bytes of this buffer.
public var size: Int {
return LLVMGetBufferSize(llvm)
}

/// Makes an iterator so this buffer can be traversed in a `for` loop.
public func makeIterator() -> UnsafeBufferPointerIterator<Int8> {
return UnsafeBufferPointer(start: start, count: size).makeIterator()
}

deinit {
LLVMDisposeMemoryBuffer(llvm)
}
}
30 changes: 30 additions & 0 deletions Sources/LLVM/TargetMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,36 @@ public class TargetMachine {
}
}

/// Emits an LLVM Bitcode, ASM, or object file for the given module to a new
/// `MemoryBuffer` containing the contents.
///
/// Failure during any part of the compilation process or the process of
/// writing the results to disk will result in a `TargetMachineError` being
/// thrown describing the error in detail.
///
/// - parameter module: The module whose contents will be codegened.
/// - parameter type: The type of codegen to perform on the given module.
public func emitToMemoryBuffer(module: Module, type: CodegenFileType) throws -> MemoryBuffer {
if case .bitCode = type {
guard let buffer = LLVMWriteBitcodeToMemoryBuffer(module.llvm) else {
throw TargetMachineError.couldNotEmitBitCode
}
return MemoryBuffer(llvm: buffer)
}
var buf: LLVMMemoryBufferRef?
var error: UnsafeMutablePointer<Int8>?
LLVMTargetMachineEmitToMemoryBuffer(llvm, module.llvm,
type.asLLVM(), &error, &buf)
if let error = error {
defer { free(error) }
throw TargetMachineError.couldNotEmit(String(cString: error), type)
}
guard let llvm = buf else {
throw TargetMachineError.couldNotEmit("unknown reason", type)
}
return MemoryBuffer(llvm: llvm)
}

deinit {
LLVMDisposeTargetMachine(llvm)
}
Expand Down